OmniAICreator/Qiita-1.07M huggingface dataset:
プロキシ配下＆日本語でJMeter4.0を起動する

# はじめに

JMeter4.0を導入した際に、日本語化とプロキシの設定で手こずりましたので、忘れない内に手順を記載します。

## Apache JMeterとは？

Webサーバーの負荷テストを実施できるPCソフトです。

類似のソフトにcurl, Postman, Insomnia等があります。これらのソフトとJMeterがどう違うのか？という話は、ここでは解説しません。


## 導入環境
以下の環境に導入しました。

- Windows 10 64bit
- Apache Jmeter 4.0 r1823414

Linuxの場合は、こちらが参考になります。
[Apache JMeter4.0 インストールとプラグイン](https://qiita.com/aske315/items/1827416f76f61a4ce262)


# JMeter4.0の導入

こちらの公式サイトにアクセスし、**Binaries**の**apache-jmeter-4.0.zip**をダウンロードしてください。
[Download Apache JMeter](https://jmeter.apache.org/download_jmeter.cgi)


![01_download.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/1f4a206d-601b-14d7-d1b4-a9fac1698ca5.png)


ダウンロードしたZIPファイルを解凍し、出てきた`apache-jmeter-4.0`フォルダをお好きなフォルダにコピーしてください。

私は、`C:\apache-jmeter-4.0` にコピーしたので、以降の説明はこれをJMeterのインストールパスとします。


# JMeterを起動

次に、JMeterを起動します。

`C:\apache-jmeter-4.0\bin\jmeter.bat`を実行します。

コマンドプロンプトが起動し、数秒待つと、ウィンドウが起動します。

![02_english.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/bdea054c-ec28-c548-275d-604c6733c1e9.png)

こんな感じの画面が表示されればインストールは成功です。一旦この画面は閉じてください。



# 日本語でJMeterを起動

JMeterは日本語でも起動できるので、その手順を紹介します。

こちらを参考にしました。
[Changing JMeter language](https://www.ubik-ingenierie.com/blog/changing-jmeter-language/)


`C:\apache-jmeter-4.0\bin`に`jmeter_ja.bat`というバッチファイルを作成し、中身を以下のようにします。

```bash
rem 言語・国を設定
set JVM_ARGS="-Duser.language=ja"

rem JMeterを起動
jmeter.bat
```

後はこのバッチファイルを実行するだけです。

![03_japanese.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/da1ded8c-128c-40d6-0ec6-414e25d994be.png)

これで日本語で起動できました。

ちなみに、このバッチファイルの`JVM_ARGS`というのは、JVM（Java仮想マシン）のオプションのようです。
JMeterの土台となっているJVMのロケールを日本にすることで、JMeterも日本語になるという仕組みです。



# プロキシ配下でJMeterを起動

ネットワーク環境によっては、プロキシ配下にPCがある場合があります。この場合、プロキシ設定をしないと、JMeterが正常に動作しません。その設定手順を紹介します。

こちらを参考にしました。
[Using JMeter behind a proxy](https://jmeter.apache.org/usermanual/get-started.html#proxy_server)

先ほどの`jmeter_ja.bat`の中身を以下のように変更します。

```bash
rem 言語・国を設定
set JVM_ARGS="-Duser.language=ja"

rem JMeterを起動
jmeter.bat -H "ホスト名" -P "ポート" -u "ユーザー名" -a "パスワード" -N "127.0.0.1|localhost"
```

ホスト名, ポート, ユーザー名, パスワードがプロキシの設定です。ご自身のネットワーク環境に応じて設定してください。
localhostの場合は、プロキシを通ってほしくないので、`-N`で指定しています。

後はこのバッチファイルを実行するだけです。

これで、プロキシ配下でもJMeterが使えるようになりました。


# JMeter Plugins Managerの導入
必須ではないですが、便利なので、**JMeter Plugins Manager**も導入します。
これはJMeter用のプラグインを管理するツールです。

こちらの公式サイトにアクセスし、**plugins-manager.jar**をクリックし、**jmeter-plugins-manager-1.3.jar**をダウンロードしてください。
[Installing Plugins](https://jmeter-plugins.org/install/Install/)

![04_plugin.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/52ad0457-408f-073f-da7f-b3b20bbc588e.png)

![05_chrome_error.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/c8bb5e47-f6fd-16c1-d44b-8c7afbdfb6ea.png)

Chromeの場合、こんな警告が表示されますが、気にせず**保存**してください。

ダウンロードしたjarファイルを、`C:\apache-jmeter-4.0\lib\ext`フォルダにコピーしてください。

JMeterを起動して、**オプション**の項目の中に**Plugins Manager**が追加されていれば、インストール成功です。

![06_success.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/efcb9755-db7b-237c-9687-586ede652691.png)


# 最後に

プロキシ配下かつ日本語でJMeterを起動することができました。

JMeterのJSONレスポンスを自動的に整形する方法も記事にしてみたので、よければ参考にしてみてください。
https://qiita.com/segur/items/cf169f9d32350a8e226f
【JavaScript TypeScript】オブジェクトを要素に持つ配列をオブジェクトのキーごとにソート

## 例えば

```
[{name: "Aさん", age: 42},{name: "Bさん", age: 23},{name: "Cさん", age: 379}]
```
みたいなデータを

```
{ name: [ 'Aさん', 'Bさん', 'Cさん' ], age: [ 42, 23, 379 ] }
```
キーごとにソートしたい！

## JavaScript(ES6)

いろんな方法がありますが、reduce使うのがベターかなと思っています。

```javascript:sortArrayByKey.js

function sortArrayByKey(arr) {
  const object = arr.reduce((prev, current) => {
    Object.keys(current).forEach((key) => {
      if(!prev[key]) prev[key] = []
      prev[key].push(current[key])
    })
    return prev
  },{})
  return object
}

const base = [{name: "Aさん", age: 42},{name: "Bさん", age: 23},{name: "Cさん", age: 379}]
const sorted = sortArrayByKey(base) // { name: [ 'Aさん', 'Bさん', 'Cさん' ], age: [ 42, 23, 379 ] }
```

## TypeScriptでの注意
むしろこちらのほうが重要で、reduceにより型が全く変わる場合の記法を知りませんでした。

```typescript:sortArrayByKey.ts
interface BaseObj {
  [key: string]: string | number;
}

interface SortedObj {
  [key: string]: (string | number)[] ;
}

function sortArrayByKey(arr: BaseObj[]): SortedObj {
  const object = arr.reduce<SortedObj>((prev, current) => {
    Object.keys(current).forEach((key) => {
      if(!prev[key]) prev[key] = []
      prev[key].push(current[key])
    })
    return prev
  },{})
  return object
}

const base = [{name: "Aさん", age: 42},{name: "Bさん", age: 23},{name: "Cさん", age: 379}]
const sorted = sortArrayByKey(base) // { name: [ 'Aさん', 'Bさん', 'Cさん' ], age: [ 42, 23, 379 ] }
```

`arr.reduce<SortedObj>`
ここで返り値の型宣言をしないと、返り値の型がBaseObjインタフェースで認識されてしまい、`push`や`return object`でエラーが発生します。
sinatraでのHTMLのエスケープとXSSについて

自分事ですが今はrubyのフレームワークのsinatraを勉強してます
そこで入力フォームからサブミットした文字にエスケープ処理をするという問題に当たりました

```html
文字を入力<input type="text" name="name">
```
例えばこのように書かれた入力フォームがあるとします

ここで`<b>あいうえお</b>`という文字列を入力して

```.rb
post '/form' do
    "#{params[:name]}"
end
```
これで出力を見ると

**あいうえお**

のように、HTMLのタグを継承して出力されてしまいます

この時に入力された文字列が悪意のあるスクリプトであった場合、それが実行されてしまい攻撃を受けることになってしまいます

これがタイトルにもあるXSS（クロスサイトスクリプティング）です

これを回避するためにエスケープ処理を導入していきたいと思います

#エスケープ処理をする
今回はsinatraでのエスケープ処理を考えていきます

```.rb
helpers do
  def h(text)
    Rack::Utils.escape_html(text)
  end
end
```

まずはこれをrbファイルに書き加えます
これを加えることで`h`メソッドでhtmlのエスケープが可能になります

```.rb
post '/form' do
    "#{h(params[:name])}"
end
```
これで実行するとエスケープ処理が施され

`<b>あいうえお</b>`

と表示されます

>参考
>Sinatra FREQUENTLY ASKED QUESTIONS: How do I escape HTML?
>>http://sinatrarb.com/faq.html#escape_html
CentOS 7 ネットワーク設定覚え書き

# CentOS 7 ネットワーク設定
CentOS 7から変わったコマンド類を覚え切れていないので覚え書きとして

デバイスの確認
nmcli device

デバイスのアドレス情報
ip addr 

デバイスごとに情報を見たい場合には
ip addr show dev ＜デバイス名＞

ルート情報
ip route

接続情報を見るには
nmcli connection show

nmcli connection show ＜ID | UUID＞

インターフェイスに自動接続を設定
nmcli connection modify ＜ID＞ connection.autoconnect yes

IPアドレス、サブネットマスクを変更
nmcli connection modify ＜ID＞ ipv4.addresses 172.16.0.100/24 

デフォルトゲートウェイを設定
nmcli connection modify ＜ID＞ ipv4.gateway 172.16.0.1

DNS設定
nmcli connection modify ＜ID＞ ipv4.dns 172.16.0.1
OpenWrt 18.06 LuCI の日本語化

# OpenWrt 18.06 LuCI の日本語化

軽くハマったのでメモ。

## パッケージ
make menuconfig でパッケージを入れる。

```
LuCI  --->
2. Modules  --->
    Translations  --->
<*> English (en)
<*> Japanese (ja)
```

## LuCI 設定
LuCI 画面で「System」→「System」→「Language & Style」→「日本語」を選択して「Save & Apply」で日本語化できる。
GCEのInstanceの停止時にDiskのスナップショットを自動で撮る

## 経緯

- 運用しているgitlabがバージョンアップに伴い動かなくなり、リカバリーに時間が取られる事件が発生した。
- これを契機に改めてバックアップについてちゃんとできているか考えたところ、Diskのバックアップ撮ってないなーと今更ながら思い、バックアップを取る仕組みを検討するに至る。

## 方針

- 定時後に自動でgitlab停止する運用をしているので、shutdown-scriptでスナップショット取ることでバックアップする。

## 実コード

- 20180828 フィルタを完全一致に変更

```shutdown-script.sh
ZONE="$(curl -s -f -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/zone | xargs basename)"
PROJECT="$(curl -s -f -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/project/project-id)"

gcloud compute disks list --filter "users=(https://www.googleapis.com/compute/v1/projects/${PROJECT}/zones/${ZONE}/instances/$(hostname))" --format "[no-heading](name)" | while read line;
do
  gcloud compute disks snapshot ${line} --zone $ZONE --async --snapshot-names=${line}-$(date "+%Y%m%d%H%M")
done
```

## 補足

- boot disk以外のdiskもスナップショットの対象とできるように、自身のインスタンスに紐づくDiskを洗い出してからスナップショットを取得するようにした。
- `gcloud compute disks snapshot`する際にasyncオプションつけることで、スナップショットの生成に90s(Preemptibeの場合30s)以上かかる場合でもちゃんとバックアップできるようにした。
redis-cliコマンドをGitからビルドしてCentOS7に入れてみた（忘れるのでメモ的な）


```bash

# テストなので、tmpにバイナリを作成して実行するためフォルダ作成
mkdir /tmp/daijin
cd /tmp/daijin

# Redis-cliコマンドのみビルド
git clone https://github.com/antirez/redis.git
cd redis
git checkout 4.0.3
make redis-cli

# 今回はtmpに作ったのでリンクしなかったが、しかるべきところでビルドすればリンクするのも悪くない。
# ln -s src/redis-cli /usr/local/bin/redis-cli

# redis serverに接続
/tmp/daijin/redis/src/redis-cli -h 127.0.0.1 -p 6379

```

yumから入れられなかったので、ビルドしてみました。

ミニマムのCentOSとかだとビルド用に何かを入れる必要があるかもしれないです。。。
Chart.jsなどで出力されるcanvasをpng画像ファイルとしてダウンロードする方法

# はじめに
最近、グラフ描画にChart.jsを使っています。
Chart.jsは無料（MITライセンス）で手軽にグラフが描けるチャートライブラリです。
Bar chartsやLine charts、Area chartsなど、よく使うチャートが予め用意されていますので、初心者でも比較的手軽に使うことができます。
[Chart.js公式サイト](https://www.chartjs.org/)

# やりたかったこと
Chart.jsで描画したcanvas上のイメージを、ボタンクリックでpng画像ファイルとしてダウンロードしたい。
（Chromeなどcanvasを右クリックで画像保存できるブラウザもありますが、別にsvgなども使っているので今回統一して「画像ダウンロード」ボタンで落とさせたい）

# 実装方法
サーバにデータを送信し、サーバ側から画像ファイルをダウンロードさせる方法もありますが、
今回ブラウザで完結させたかったため下記のように実装。

```javascript:canvas2png.js（抜粋）
var canvas = $("#myCanvas")[0];
$("body").append("<a id='image-file' class='hidden' type='application/octet-stream' href='" + canvas.toDataURL("image/png") + "' download='mycanvas.png'>Download</a>");
$("#image-file")[0].click();
$("#image-file").remove();
```
※jQueryとBootstrap使っています。

#おわりに
IEでは動作しません...
はやくIE終わって欲しい...
macOSのシステムアイコンのありか

##ファイルアイコンの場所
`/System/Library/CoreServices/C­oreTypes.bundle/Contents/Resou­rces`

<img width="400" alt="スクリーンショット 2018-08-27 16.32.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/67153/2e2d669c-c3be-e3c8-4f79-27b1c0f8bf3c.png">

##メニューバーのアイコンの場所
`/System/Library/CoreServices/Menu Extras/`配下のアプリケーションの中のリソース

例:
`/System/Library/CoreServices/Menu Extras/Bluetooth.menu/Contents/Resources`

<img width="400" alt="スクリーンショット 2018-08-27 16.37.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/67153/372382ef-bcb1-b54d-3819-c4d10013b75e.png">

##余談
メニューバーのアイコンのデフォルトの高さを知ろうと思って調べたのにPDF（ベクターファイル）でがっかり
Windows 10 1803にアップデート後、印刷しようとすると「ドライバーが無効です」と言われたら

ドライバー再インストールなどなど行ってもダメな場合、下記手順で修正できることがあります。

https://answers.microsoft.com/en-us/windows/forum/windows_10-hardware/error-0x000007d1-on-printer/83315d1e-1daa-4200-bbcf-8131f8a4071e?page=1
TheSenselMorphをTouchDesignerで使う

#TheSenselMorph
概要：https://sensel.com/

#TheSenselMorph側の設定
1. まずはTheSenselMorphの設定を行うアプリケーションを用意する.
->https://sensel.com/pages/support

2. NoOverlay(TheSenselMorphの上に何も置かない場合)の設定の時、画像のような感じになっているはずです.
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/184790/e7dca8ad-c8c9-f4bf-f604-708eba2ab57b.png)


3.画面左上に表示されているSend Map To Marphをクリックすることで今までの設定をSenselの方に焼きこむ.

- MPEとは<br>
ROLISeaboardやtheLinnstrumentといった1つのインターフェースで同時に複数のパラメータを制御できるデバイスが存在する.それらのパラメータのデータをmidiを用いて通信する手法である.

#TouchDesigner側の受信設定
1.Senselを入力midiデバイスを追加する
Dialogs->MIDI DEVICE MAPPER内でin DeviceにSenselを追加する.
![midi.png](https://qiita-image-store.s3.amazonaws.com/0/184790/47dfa0c2-39fa-eade-7513-5dd84045db93.png)

2.midiinオペレータを使うことで値を取得することで出来る.取得される値としてはタッチした座標、押され続けている際の指圧、押された瞬間の指圧？があります.


#サンプル
一点しか使ってないですが、座標でカメラ移動、指圧はParticleのTurbulenceを制御しています.
https://github.com/KeitoTakaishi/Sensel_Sample

#補足
座標を取る際の注意事項としてSenselに焼きこむ設定で座標値をAbsoluteにしておいたほうが使いやすいかもしれないです.
![morph.png](https://qiita-image-store.s3.amazonaws.com/0/184790/5e8b868e-69ea-d15e-072d-9638afa93f57.png)
存在しない要素に対して.offset().topするとエラーになる

topに限った話ではありませんが、以下のようにするとエラーになります。

```javascript
$('.notExistElem').offset().top
```

これはHTMLに要素を記述していない場合だけでなく、`display: none`の場合にも起こるようです(`visibility: hidden`は大丈夫)。

エラーを防ぐためにはif文などで要素の存在を調べてから処理しましょう(`.length`などを使うと良いです)。
Maximaの入門書

[●テキスト本体（PDF形式32ページ:718KB）](http://www.k-techlabo.org/www_maxima/maxima_main.pdf)　2019/08/15更新
（[→ミラーサイトからDL](https://ktechlabo.xsrv.jp/www_maxima/maxima_main.pdf)）
－－－－－－－－－－－－－－－－－－－－－
　
(2018/08/27)
Maximaの初歩的な解説資料を配布しています．
　
　各種方程式の求解や，線形代数，微積分，級数展開の作業は煩わしいことが多くて，数学的な計算処理は数式処理システムを使用するのが便利です．
　
　このテキストは2013年から作成しはじめて，研究仲間や学生達に配っていました．テキストのメンテナンスをやった機会にネットで公開することにしました．
著作権は保持していますが「フリーソフト」とします．印刷・再配布も自由にしていただいて結構ですが，その際は内容を変更しないでください．
　
もし不備な点がありましたら，是非ご一報くださいませ．できるだけ迅速に修正します．
　
－－－－－－－－－－－－－－－－－－－－－
　理系の人でも，試験が終わってしまうと折角憶えた公式を忘れてしまうことが多いです．数学を得意とする人でも，長い数式を手作業で間違いなく処理するのは難しいです．
　実際に理系分野の研究者も，研究成果を論文として発表する前には数式を数式処理システムで検算します．
　
今や数式処理システムは理系／文系関係なく重要なツールとなっています．
　
　
数式の計算を必要とするアプリケーションプログラムを開発する際は，Python+SymPyという組み合わせが良いかと思いますが，人が自在に数式を扱うには，それなりのインターフェースを備えた数式処理システム良いですね．
　
[PythonとSymPyに関する資料はこちら](https://qiita.com/KatsunoriNakamura/items/b465b0cf05b1b7fd4975)で公開しています．
　
## 補足（更新に関すること，ご案内など）
－－－－－－－－－－－－－－
【補足】(2019/08/15)
　誤りをいくつか修正しました．
ご指摘くださった方，どうもありがとうございます．

-----
written by 中村勝則
ドシロウトがマストドンボット作ってみた

## ０．初めに

私はエンジニアではないただのドシロウトです。

マストドンを利用しており、自動で通知できるボットみたいものを動かしてみたくなりました。

そこで私が一番使いやすいGoogle Apps Scriptでボットを作れないか試してみました。

なお、マストドンにアクセスするにはトークンが必要となりますが、以下のWEBサービスを利用して取得しています。

> Access Token Generator for Mastodon API
> https://takahashim.github.io/mastodon-access-token/

## １．作ったもの

用意したのはGoogleスプレッドシートとGASのスクリプトだけです。

## ２．Googleスプレッドシート

分かりづらいかもしれませんが下表のように作成しました（カッコ内は列番号）

| 行番号 | 曜日(0) | 投稿する文面の内容(1) |
|:-:|:-:|:-:|
| 1 | 日曜日 | 投稿文面 |
| 2 | 月曜日 | 投稿文面 |
| 3 | 火曜日 | 投稿文面 |
| 4 | 水曜日 | 投稿文面 |
| 5 | 木曜日 | 投稿文面 |
| 6 | 金曜日 | 投稿文面 |
| 7 | 土曜日 | 投稿文面 |

曜日別に投稿文面が設定できるようにしてあります。

## ３．GASのスクリプト

GASのコードは以下となります。

```javascript:msttou.gs
function msttou() {
  // アクセストークンをスクリプトプロパティから取得
  var valuex = PropertiesService.getScriptProperties().getProperty('token01');

  // 投稿内容取得
  var toukoux= touget();
  if (toukoux == 'none') {
    console.log('本日投稿なし');
    return false;
  };
  // post用URL生成
  var posturl = 'https://(マストドンのURL)/api/v1/statuses';

  // POSTで送る（JSON形式）
  var data = {
    'access_token': valuex,
    'status': toukoux
  };
  
  var options = {
    'method' : 'post',
    'contentType': 'application/json',
    // Convert the JavaScript object to a JSON string.
    'payload' : JSON.stringify(data)
  };
  
  UrlFetchApp.fetch(posturl, options);

}

function touget() {

  var date = new Date();
  var youbiidx = date.getDay(); /* 曜日の取得　０は日曜 */
  var rtntou = 'none';
  // スプレッドシート名：mstdntou　の取得
  var files = DriveApp.getFilesByName('mstdntou');

  if (files.hasNext()) {
    
    var spreadsheet = SpreadsheetApp.open(files.next());
    // シート番号０を取得
    var sheet = spreadsheet.getSheets()[0];
    var var1=sheet.getDataRange().getValues();
    for (var rowidx in var1) {
      if (rowidx == youbiidx) {
        if (var1[rowidx][1] == '通知なし') {
        } else {
          var rtntou = var1[rowidx][1];
        };
      };
      
    };

  };
  return rtntou;

}
```

* 関数msttouをトリガーで1日１回実行するように設定しています。

* 一応、トークンを隠すためにスクリプトプロパティを使っています。

> Class PropertiesService
> https://developers.google.com/apps-script/reference/properties/properties-service

## 4．まとめ

マストドンでボットを使いたい人には簡単でいいと思います。

やっぱりGAS便利ですね。


以　上
SMTPのやり取りを検証したかった


メールの調査のためEHLOとHELOを切り替えたりした場合のレスポンスなどを確認したかった。
その際、メールサーバ立ててパケットキャプチャを実施してメールの監視なども行っていたが、rubyスクリプトで監視出来るようにスクリプトを用意したので備忘録としてメモ


プログラムはこんな感じsmtpライブラリを使って
smtp.set_debug_outputをする事で送受信の内容が見えた。
プログラム中の　TO = "なんとかかんとーか@gmail.com" は要書き換え。


```ruby:smtp.rb
#!/usr/bin/env ruby

require 'net/smtp'

# dig -t MX  gmail.com から取得
SMTP_SERVER = 'gmail-smtp-in.l.google.com'
TO = 'なんとかかんとーか@gmail.com'

smtp = Net::SMTP.new(SMTP_SERVER, 25)
smtp.set_debug_output $stderr

# SMTPのEHLOの代わりにHELOコマンドを使って送信したい
# smtp.esmtp = false

smtp.start do
  message = <<-END_MAIL
From: "メール送り主" <#{TO}>
To: #{TO}
Subject: メール配信テスト
Date: Sat, 23 Jun 2001 16:26:43 +0900
Message-Id: <#{Time.now.to_i}@gmail.com>

メール配信テスト
  END_MAIL

  response = smtp.send_message(message, TO, TO)
  p response
end
```

上記プログラムを実行すると以下のようなメッセージになる。
送信の時にEHLOコマンドを実行して、サポートされている機能などが返ってきていることが確認出来る。

```
Connection opened: gmail-smtp-in.l.google.com:25
-> "220 mx.google.com ESMTP 6-v6si8033943pgl.517 - gsmtp\r\n"
<- "EHLO localhost\r\n"
-> "250-mx.google.com at your service, [210.128.134.30]\r\n"
-> "250-SIZE 157286400\r\n"
-> "250-8BITMIME\r\n"
-> "250-STARTTLS\r\n"
-> "250-ENHANCEDSTATUSCODES\r\n"
-> "250-PIPELINING\r\n"
-> "250-CHUNKING\r\n"
-> "250 SMTPUTF8\r\n"
<- "MAIL FROM:<なんとかかんとーか@gmail.com>\r\n"
-> "250 2.1.0 OK 6-v6si8033943pgl.517 - gsmtp\r\n"
<- "RCPT TO:<なんとかかんとーか@gmail.com>\r\n"
-> "250 2.1.5 OK 6-v6si8033943pgl.517 - gsmtp\r\n"
<- "DATA\r\n"
-> "354  Go ahead 6-v6si8033943pgl.517 - gsmtp\r\n"
writing message from String
wrote 222 bytes
-> "250 2.0.0 OK 1535351007 6-v6si8033943pgl.517 - gsmtp\r\n"
#<Net::SMTP::Response:0x00007fac5905e4b8 @status="250", @string="250 2.0.0 OK 1535351007 6-v6si8033943pgl.517 - gsmtp\n">
<- "QUIT\r\n"
-> "221 2.0.0 closing connection 6-v6si8033943pgl.517 - gsmtp\r\n"
```


参考: https://docs.ruby-lang.org/ja/latest/class/Net=3a=3aSMTP.html
ServerlessでAPI GatewayのオーソライザーをCORS対応する方法

### 本記事について
API GatewayのオーソライザーをCORSできるようにするための設定を、Serverless Framework上で行う方法について記載します。

詳しくは下記に記載されているものを、概要を加えて転記いたします。

- https://serverless.com/blog/cors-api-gateway-survival-guide/#cors-with-custom-authorizers
- https://github.com/serverless/serverless/issues/3896#issuecomment-326721971

## 解説
### CORSについて
CORSなAPIにするには、APIのレスポンスヘッダーで「Access-Control-Allow-Headers」「Access-Control-Allow-Origin」を返す必要があります。

API Gatewayで[リソース]-[CORSの有効化]を行うと、API GatewayがCORSに必要なもろもろの設定を行ってくれます。

そのAPI GatewayのCORS設定を、Serverlessで行うには、[公式サイトに記載](https://serverless.com/blog/cors-api-gateway-survival-guide/)のとおり、``serverless.yml``で「cors: true」と記載することで行えます。

### オーソライザーのCORSについて
APIでオーソライザーを使った場合のCORSの設定は、上記に加えもうひと手間必要になります。

認証に成功した場合は、本来のAPIが呼び出されるのでCORSのレスポンスの設定がされていて問題ありませんが、認証に失敗した場合は、APIは呼び出されず、オーソライザーからレスポンスが返されるため、別途オーソライザーからのエラー返答用にCORSの設定が必要になります。

この設定を行わないと、認証が失敗して応答があっても、クライアントでCORSエラーが発生して、認証エラーを検知することができなくなってしまいます。

## 手順(API Gatewayを使った場合)
「401 Unauthorized レスポンス」と「500 Authorizer Failure レスポンス」で下記のレスポンスヘッダーを返すようにします

- 「Access-Control-Allow-Headers」：「'*'」
- 「Access-Control-Allow-Origin」：「'*'」

設定は[ゲートウェイのレスポンス]で行います。

![ss01.png](https://qiita-image-store.s3.amazonaws.com/0/100574/a6a83d62-d686-7983-b7f0-4d91497c8629.png)

### 401・500の違い
[公式ヘルプに記載](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html)のとおり、``callback("Unauthorized")``でエラーを返した場合は「401 Unauthorized」、「"Unauthorized"」以外でエラーを返した場合は「500 Internal Server Error レスポンス」になります。（本記事では両方を設定しています）

## 手順(Serverlessを使った場合)
設定は上記API Gatewayを使った場合と同じですが、API Gatewayを直接変更できないため、serverless.ymlの「resources」で、API Gateway設定を行います。

```yaml:serverless.yml
resources:
  Resources:
    GatewayResponse401:
      Type: 'AWS::ApiGateway::GatewayResponse'
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
        ResponseType: UNAUTHORIZED
        RestApiId:
          Ref: 'ApiGatewayRestApi'
        StatusCode: '401'
    GatewayResponse500:
      Type: 'AWS::ApiGateway::GatewayResponse'
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
        ResponseType: AUTHORIZER_FAILURE
        RestApiId:
          Ref: 'ApiGatewayRestApi'
        StatusCode: '500'
```
以上で、認証失敗した場合でもレスポンスヘッダーが返されるようになり、オーソライザーを使ったAPIでもCORSが行えるようになります。

## その他
ServerlessはCloudFormationでAWSのリソースを作成しており、ゲートウェイレスポンスの設定はCloudFormationの[GatewayResponseの記述](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-gatewayresponse.html)とほぼ同じです。

## 元記事
- [ServerlessでAPI GatewayのオーソライザーをCORS対応する方法](https://www.kwbtblog.com/entry/2019/02/19/050110)
[メモ] reduxのformikを使ったformでmutationを使う

##参考
https://github.com/jaredpalmer/formik/issues/70
https://gist.github.com/mwickett/2aecfdeea40daa07d39e11922ae1fe20

react-apolloのgraphqlメソッドのリファレンス
https://www.apollographql.com/docs/react/api/react-apollo.html#graphql
react-apolloのgraphqlメソッドにmutation使った場合のconfigのリファレンス
https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options

```js
const handleSubmit = (payload, { props }) => {
  const {
    uiActions: { sendNotification, closeAccountUpdateDialog },
    currentAccountId,
    updateCurrentAccount
  } = props;

  const { lastName: last_name, firstName: first_name } = payload;

  updateCurrentAccount({
    variables: { id: currentAccountId, last_name, first_name }
  })
    .then(() => {
      sendNotification({
        level: 'success',
        message: 'アカウント情報を更新しました。'
      });

      closeAccountUpdateDialog();
    })
    .catch(e => {
      sendNotification({
        level: 'error',
        message: 'アカウント情報更新に失敗しました。'
      });

      closeAccountUpdateDialog();
    });
};

class AccountUpdateDialog extends Component<Props> {
  props: Props;

  render() {
    const { values, handleChange, handleSubmit, uiActions, ui } = this.props;

    return (
      <form id="account-update-form" onSubmit={handleSubmit}>
        <Dialog
          open={this.props.open}
          onClose={uiActions.closeAccountUpdateDialog}
        >
          <DialogTitle>アカウント情報更新</DialogTitle>
          <DialogContent>
            <DialogContentText>基本情報</DialogContentText>
            <TextField
              margin="dense"
              id="lastName"
              label="姓"
              type="text"
              fullWidth
              value={values.lastName}
              onChange={handleChange}
            />
            <TextField
              margin="dense"
              id="firstName"
              label="名"
              type="text"
              fullWidth
              value={values.firstName}
              onChange={handleChange}
            />
          </DialogContent>
          <DialogActions>
            <Button
              onClick={uiActions.closeAccountUpdateDialog}
              color="primary"
            >
              閉じる
            </Button>
            <Button type="submit" form="account-update-form" color="primary">
              更新
            </Button>
          </DialogActions>
        </Dialog>
      </form>
    );
  }
}

const AccountUpdateDialogForm = compose(
  graphql(UPDATE_CURRENT_ACCOUNT, { name: 'updateCurrentAccount' }), // nameを指定しないとprops.mutate()になる。
  withFormik({
    validationSchema: yup.object().shape({
      lastName: yup.string(),
      firstName: yup.string()
    }),
    handleSubmit
  })
)(AccountUpdateDialog);
```
Donkey Car学習(Mac側)

# 関連Qiita

- [Donkey Carの作り方(RasPi側)
](https://qiita.com/akira-sasaki/items/c37468e88c9bbd739a65)
- [Donkey Car PS3 Joystick(RasPi側)](https://qiita.com/akira-sasaki/items/987ba17060637cff2c3e)
- [Donkey Carで動きそうなラジコン](https://qiita.com/akira-sasaki/items/753106d6ad9f62a31a40)
- [Donkey Carの作り方(Mac側)
](https://qiita.com/akira-sasaki/items/66f31a969712d8dea758)
- [Donkey Carの作り方(Windows側)](https://qiita.com/akira-sasaki/items/dc06b0ca21821fc8ef48)
- [Donkey Car Emulator(Mac側)](https://qiita.com/akira-sasaki/items/5e838b4f5125e25b4523)
- [Donkey Car学習](https://qiita.com/akira-sasaki/items/e0cc64dae5565b38987d)
- [Donkey Car Commandメモ](https://qiita.com/akira-sasaki/items/4097f9bdea46fb654a04)
- [Donkey Car Officialのドキュメント(リンク)](https://docs.donkeycar.com/)
- [AWS DeepRacerまとめ](https://qiita.com/akira-sasaki/items/c29282c281ca274d2691)

## 教師データの作成(RaspberryPi側)

```
$ cd ~/mycar
$ python manage.py drive
```

<img width="1021" alt="controller.png" src="https://qiita-image-store.s3.amazonaws.com/0/63450/ffd3f0fe-982e-a89c-c4c4-ca9fee3659cf.png">

トレーニングデータは、~/mycar/data以下に保存される。

## 教師データの学習(Mac側)

教師データをRaspberryPiから、Macにrsyncする。

```
$ rsync -r pi@192.168.86.41:~/mycar/data/ ~/mycar/data/
```

```
$  ls data
tub_01_18-08-27	tub_02_18-08-27
```
Mac側には、tub_日付のフォルダが教師データ作成の度にふえていく。

```
$ donkey tubclean .
```
いらないデータを削除する。

```
$ python ~/mycar/manage.py train --tub=~/mycar/data/tub_01_18-08-27 --model=./models/mypilot
```

これで学習開始。

## 学習済みモデルをRaspberryPiに戻す

```
$ rsync -r ~/mycar/models/ pi@<your_ip_address>:~/mycar/models/
```

## 学習済みモデルでDonkeyを動かす

RaspberryPi側にログイン。

```
$ python manage.py drive --model ~/mycar/models/mypilot
```

or

Web画面のmodel & pilotから、autopilotを選ぶ。
無料ではじめるMinecraft Server運営 殴り書きメモ

#概要
「マイクラ鯖建ててみたいな～」くらいの人に向けた、お金を全くもしくは、ほとんど掛けずに、そこそこ良質なサーバーを建てるためのサービスをまとめてみました。

気が向いたら書き足す。

#仮想マシン
###Google Compute Engine (https://cloud.google.com/compute/)
1年間、約3万円分($300)のクレジットが無料で利用できます。
Google公式からセットアップドキュメントも提供されています。(https://cloud.google.com/solutions/gaming/minecraft-server)

###Vultr (https://www.vultr.com/benchmarks/)
小・中規模の鯖なら、月500円程度で建てられるんじゃないでしょうか。

#サーバーMod
###Spigot (https://www.spigotmc.org/wiki/buildtools/)
CraftBukkitをもとにしたサーバーModです。BuildToolsを使ってビルドする必要があります。くれぐれも非公式なサイトからjarファイルを直接ダウンロードしてくるようなことはやめましょう。

#通話・チャット
###Discord (https://discordapp.com/)
役割毎に部屋を作って管理することができます。最近ではすでに入れている方も多くなってきたので、スムーズに運営がはじめられるのではないでしょうか。

###Slack (https://slack.com/)
コマンドをこっからサーバーへ投げることもできます。

- - -
以下、プラグインまで開発する人向け

#開発環境
###IntelliJ IDEA (https://www.jetbrains.com/idea/)
Minecraft Developmentプラグインを利用すれば、すぐにMinecraft用プラグイン開発がはじめられます。

#ソース共有
###Github (https://github.com/)
プラグインを共同で開発する際におすすめです。Projects機能も活用しましょう。
【PHP】年月日が配列で渡ってくるときのバリデーション


## 目的

入力フォームの都合で次のような配列の形で年月日のデータが渡される。

```php
$date = [
    'year'  => 1990,
    'month' => 1,
    'day'   => 1,
];
```


このときに

* 所定の型・形式なのか
* 妥当な日付なのか

を検証したい。

なお、外部からの入力内容をチェックする想定なので

* 渡されるデータの型は保証されていない
* 数値 (int) が入る箇所には、「数値 (int)」「数値 (int) として解釈できる文字列」の両方を許可する

とする。

## コード

日付の妥当性検証には PHP 組み込みの `checkdate()` を使う。

* [checkdate — グレゴリオ暦の日付/時刻の妥当性を確認します - PHP.net](http://php.net/manual/ja/function.checkdate.php)

```php
/**
 * @param mixed $value チェック対象のデータ
 * @return bool 所定の形式に従った、妥当な日付の場合に true
 */
function isValidDateArray($value): bool
{
    if (!is_array($value)) {
        return false;
    }

    $expectedKeys = ['year', 'month', 'day'];
    foreach ($expectedKeys as $key) {
        // キーが存在しない、またはそのキーに対する値が整数でなければ false を返す
        if (!isset($value[$key]) || (filter_var($value[$key], FILTER_VALIDATE_INT) === false)) {
            return false;
        }
    }

    return checkdate($value['month'], $value['day'], $value['year']);
}
```

`filter_var()` による整数の検証についてはこちらを参照。

* [PHP:文字列が整数かの検証にはis_numeric, ctype_digit, filter_varどれが適切か？@suin - Qiita](https://qiita.com/suin/items/988e29f71a74456fd42f)

用途に合わせて整数の検証ロジックは書き換えるとよい。


## 動作確認

* PHP 7.1.18

以下の assertion が全て満たされていることを確認。

```php

$dataSets = [
    '正常系_数値で指定された場合にtrueを返すこと' => [
        'expected' => true,
        'value'    => [
            'year'  => 1990,
            'month' => 1,
            'day'   => 1,
        ],
    ],
    '正常系_文字列で指定された場合にtrueを返すこと' => [
        'expected' => true,
        'value'    => [
            'year'  => '1990',
            'month' => '1',
            'day'   => '1',
        ],
    ],
    '配列が渡されていない場合にfalseを返すこと' => [
        'expected' => false,
        'value'    => 1,
    ],
    'キーが足りていない場合にfalseを返すこと' => [
        'expected' => false,
        'value'    => [
            'year'  => 1990,
            'month' => 1,
        ],
    ],
    '正常系＿余分なキーが存在している場合でもtrueを返すこと' => [
        // NOTE: 今回ではこの形は許容している、必要なら余分なキーの存在チェックを足す
        'expected' => true,
        'value'    => [
            'year'  => 1990,
            'month' => 1,
            'day'   => 1,
            'foo'   => 'bar'
        ],
    ],
    '非整数が渡された場合にfalseを返すこと' => [
        'expected' => false,
        'value'    => [
            'year'  => 'a',
            'month' => 1,
            'day'   => 1,
        ],
    ],
    '不正な日付が渡された場合にfalseを返すこと' => [
        'expected' => false,
        'value'    => [
            'year'  => 1990,
            'month' => 2,
            'day'   => 29,
        ],
    ],
    'うるう年の2月29日が渡された場合にtrueを返すこと' => [
        'expected' => true,
        'value'    => [
            'year'  => 1980,
            'month' => 2,
            'day'   => 29,
        ],
    ],
];

foreach ($dataSets as $testCase => $dataSet) {
    assert(isValidDateArray($dataSet['value']) === $dataSet['expected'], $testCase);
}
```
Donkey Carの作り方(Mac側)

# 関連Qiita

- [Donkey Carの作り方(RasPi側)
](https://qiita.com/akira-sasaki/items/c37468e88c9bbd739a65)
- [Donkey Car PS3 Joystick(RasPi側)](https://qiita.com/akira-sasaki/items/987ba17060637cff2c3e)
- [Donkey Carで動きそうなラジコン](https://qiita.com/akira-sasaki/items/753106d6ad9f62a31a40)
- [Donkey Carの作り方(Mac側)
](https://qiita.com/akira-sasaki/items/66f31a969712d8dea758)
- [Donkey Carの作り方(Windows側)](https://qiita.com/akira-sasaki/items/dc06b0ca21821fc8ef48)
- [Donkey Car Emulator(Mac側)](https://qiita.com/akira-sasaki/items/5e838b4f5125e25b4523)
- [Donkey Car学習(Mac側)](https://qiita.com/akira-sasaki/items/e0cc64dae5565b38987d)
- [Donkey Car Commandメモ](https://qiita.com/akira-sasaki/items/4097f9bdea46fb654a04)
- [Donkey Car Officialのドキュメント(リンク)](https://docs.donkeycar.com/)
- [AWS DeepRacerまとめ](https://qiita.com/akira-sasaki/items/c29282c281ca274d2691)

コンテンツは
https://faboplatform.github.io/DonkeyDocs/1.%E5%AD%A6%E7%BF%92%E7%94%A8PC/1.dev/
にUpdateしています。
Donkey Carの作り方(RasPi側)

# 関連Qiita

- [Donkey Carの作り方(RasPi側)
](https://qiita.com/akira-sasaki/items/c37468e88c9bbd739a65)
- [Donkey Car PS3 Joystick(RasPi側)](https://qiita.com/akira-sasaki/items/987ba17060637cff2c3e)
- [Donkey Carで動きそうなラジコン](https://qiita.com/akira-sasaki/items/753106d6ad9f62a31a40)
- [Donkey Carの作り方(Mac側)
](https://qiita.com/akira-sasaki/items/66f31a969712d8dea758)
- [Donkey Carの作り方(Windows側)](https://qiita.com/akira-sasaki/items/dc06b0ca21821fc8ef48)
- [Donkey Car Emulator(Mac側)](https://qiita.com/akira-sasaki/items/5e838b4f5125e25b4523)
- [Donkey Car学習(Mac側)](https://qiita.com/akira-sasaki/items/e0cc64dae5565b38987d)
- [Donkey Car Commandメモ](https://qiita.com/akira-sasaki/items/4097f9bdea46fb654a04)
- [Donkey Car Officialのドキュメント(リンク)](https://docs.donkeycar.com/)
- [AWS DeepRacerまとめ](https://qiita.com/akira-sasaki/items/c29282c281ca274d2691)

コンテンツは
https://faboplatform.github.io/DonkeyDocs/2.RCCar(RaspPi3)/02.rasppi/
にUpdateしています。
Rails x Bootstrap4 x nested_attributesフォームのデザインパターン

- よく使うのでメモ書きに、最終的にこんな感じになります。

![nested_pattern1.gif](https://qiita-image-store.s3.amazonaws.com/0/106711/93719bd3-68af-0cb1-dc90-13611f3838a8.gif)

- 完成後のリポジトリは[こちら](https://github.com/DialBird/nested_attr_sandbox)

## インストール
- `nested_attributes`のフォームを作る時に[cocoon](https://github.com/nathanvda/cocoon)というGemを使うと便利なので、それを使います。

```rb
gem 'cocoon'
```
- cocoonを使うためには、Gemのインストールと、`assets/application.js`への登録が必要です。

```js
//= require cocoon
```

- あとBootstrap4をRailsで使うので、あらかじめ設定しておいてください。（[こちらの記事](https://qiita.com/NaokiIshimura/items/c8db09daefff5c11dadf)にわかりやすくまとめてありました。@NaokiIshimuraさんありがとうございます。）

## モデルへの実装
- 今回はわかりやすく`User`と`Dog`を一対多で関連づけます。（`nested_attributes`を忘れない。）
- またコードの簡略化のため、それぞれのモデルのパラメーターを配列にして定数化しておきます。

```rb
class User < ApplicationRecord
  ATTRIBUTES = %i[name].freeze

  has_many :dogs, dependent: :destroy, inverse_of: :user
  accepts_nested_attributes_for :dogs, allow_destroy: true, reject_if: :all_blank
end

class Dog < ApplicationRecord
  # nested_attributesの都合上、idと_destroyを加えている。
  ATTRIBUTES = %i[id _destroy name].freeze

  belongs_to :user
end
```

## コントローラーへの実装
- `nested_attributes`の**StrongParameter**の対応を忘れない。

```rb
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render :new
    end
  end

  private

  def user_params
    params
      .require(:user)
      .permit([*User::ATTRIBUTES, dogs_attributes: Dog::ATTRIBUTES])
  end
end
```

## ビューの実装
- ビューの構成は以下の通りです。（今回使う箇所だけ）
- cocoonの仕様で、子要素のテンプレートになる`_〇〇_fields.html.slim`を作らないといけないことに注意してください。
- cocoonのビュー周りの注意点は[公式のリポジトリ](https://github.com/nathanvda/cocoon)にまとめてあるので、気になった方は確認してください。

```
app/views/users/
├── _dog_fields.html.slim
├── new.html.slim
└── show.html.slim
```

- 実際のコードは以下。

```slim
/ show.html.slim
p
  strong Name:
  = @user.name

ul
  - @user.dogs.each do |dog|
    li = dog.name

=> link_to 'Edit', edit_user_path(@user)
'|
=< link_to 'Back', users_path
```

```slim
/ new.html.slim
h2.py-3 New use
= form_for @user do |f|
  .form-group.row
    .col-md-3
      = f.label :name
    .col-md-9
      = f.text_field :name, class: 'form-control'
  .form-group.row
    .col-md-3
      = f.label :dogs
    .col-md-9.ml-auto
      #dogList
        = f.fields_for :dogs do |dog|
          = render 'dog_fields', f: dog
      = link_to_add_association f, :dogs, class: "btn btn-link", data: { association_insertion_node: "#dogList", association_insertion_method: "append" } do
        = fa_icon "plus", text: "アイテムを追加"
  = f.submit 'Submit', class: 'btn btn-success w-100'
```

```slim
/ _dog_fields.html.slim
.nested-fields.mb-3
  .form-row
    .col-md-10
      = f.text_field :name, placeholder: '名前', class: 'form-control'
    .col-md-2
      = link_to_remove_association "削除", f, class: "btn btn-danger"
```

- cocoonの仕様上、**nested-fieldsクラスを子要素につけないと追加されません**。
- これにより、「追加ボタン」の位置を一番下にしたまま、新しいフォームが追加されます。

## まとめ
- こんな感じで作ればすんなりと`nested_attributes`のフォーム実装ができるかと思います！
Git Bashでアカウントをリポジトリごとに分ける備忘録。

他に方法あるんでしょうが、これでいけたってやつ。
仕事ではhub、プライベートはlabで管理してます。
Git Bashが入ってるwin10です。

#①.git>configを編集

ファイル下部に下記追加

```
[user]
	name = アカウントID
	email = メールアドレス@gmail.com
```

#②Git Bashで設定

該当リポジトリで右クリック→「Git Bash Here」

```
git config user.name "アカウントID"
git config user.email "メールアドレス@gmail.com"
```

私はTortoiseGitを使ってるので
該当リポジトリで右クリック→TortoiseGit→設定
でユーザー情報が変わってるか確認してました。
ずっとTortoiseGitの設定でどうにかできるのかーっていじってたけどグローバルで変わっちゃって焦った。
MacでCPUの詳細を調べる

`Finder`→`このMacについて`で`2.9 GHz Intel Core i5`などと、どのCPUが使われいるか分かるが、正確な型番などの詳細までは分からない。ターミナルで以下のコマンドを打つと、調べることができる。

```
sysctl machdep.cpu.brand_string
```

私のMacの場合、以下の様に表示された。

```
machdep.cpu.brand_string: Intel(R) Core(TM) i5-5287U CPU @ 2.90GHz
```

それを元にインテルのサイトで仕様を確認できる。
[インテルのCPUの仕様]
(https://ark.intel.com/ja#@PanelLabel122139)

また、CPUの性能は以下のサイトで調べられる。
[CPU Benchmarks]
(https://www.cpubenchmark.net/high_end_cpus.html)


さらに詳細を見るには以下のコマンド

```
sysctl -a machdep.cpu
```


## 参考
[MacのCPUの型番や詳細情報の調べ方]
(https://webnexty.com/mac-cpu/)
SlackのAPI経由でのメンションの仕様変更(2018/9/12～)

## TL;DR;
- Slack API経由でのメンション方法が変わる
    - [公式アナウンス](https://api.slack.com/changelog/2017-09-the-one-about-usernames)
- 2017/9/11に変更を始めており、2018/9/12には完全に移行される
- 新形式は `<@user_id>`
- 旧形式の `<@username>` は使えなくなる
- メッセージ中の `@username` がメンションになる `link_names` オプションも廃止される

## 変更内容
仕様変更のうち、関係の深い内容をいくつかピックアップします。

### Mentioning users in messages より
メッセージ中のメンションの記法についてです。

> The user mentioning syntax <@W123|bronte> is now deprecated and will eventually be removed. 

`<@W123|bronte>` 記法は廃止予定であり、そのうち消すよ。

> Use the simpler user ID-only form <@W123> instead

代わりに `<@user_id>` を使ってね。

> Using link_names when posting messages is also deprecated. We'll continue matching @mentions with usernames, but for now please mention users with the <@W123> user ID format instead.

`link_names` オプションは廃止予定。今のところ `@username` も取り扱うけど、今後は `<@user_id>` 形式を使ってね。

> The undocumented approach to mentioning users via the API — <@username> — will no longer function

`<@username>` っていう隠しコマンドは今後使えなくなるよ(…あれ非公式のものだったのか)。

#### 補足
`@channel`, `@here`, `@everyone` は `<!channel>`, `<!here>`, `<!everyone>` が対応している。
https://api.slack.com/docs/message-formatting#linking_to_urls

## 対応方法
1. `user_id` を取得する
    - 個別: Slackクライアントのプロフィールから取得(member IDという名前になっている)
        - @ryo-yamaoka さんの記事: [SlackのIncoming Webhooksでメンションを飛ばす方法](https://qiita.com/ryo-yamaoka/items/7677ee4486cf395ce9bc)にキャプチャ付きの解説があります
    - チーム内一括: API [users.list](https://api.slack.com/methods/users.list)で取得
        - 取得したJSON中の `id` がこれに該当する
2. APIからのメンションをすべて新形式の `<@user_id>` に変更する
一年ぶりにvagrantを使おうとしたら出たエラーとその解決方法

一年ぶりにvagrantを使おうとしたら２つほどエラーが出たので、その解決法書いておきます。
調べればすぐ他の記事が出て来ますが、自分の備忘録として投稿します。

# Implementation of the USB 2.0 Controller not found

このエラーは「Oracle VM VirtualBox Extension Pack」がインストールされてないと出ます。
ライセンスの関係で同封して配布出来ないので分けて配布しているみたいです。
[こちらのページ](https://www.virtualbox.org/wiki/Downloads)にある「VirtualBox 5.2.18 Oracle VM VirtualBox Extension Pack」の「All supported platforms」からダウンロードできます。
（バージョン番号は異なる場合があります）
<img width="998" alt="スクリーンショット_2018-08-27_14_15_00.png" src="https://qiita-image-store.s3.amazonaws.com/0/83495/923ce482-78a4-a5bf-187b-afc37c0b8828.png">

このとき自分は過去のバージョン探すのがメンドくさいので、Virtualboxを最新版にアップデート、Extension Packも最新のものを入れました。

# Vagrantで共有フォルダのマウントに失敗する

Guest Additionsのバージョンが正しくないと発生します。
正しくない場合は手動でGuest Additionsを再インストールする必要があります。
多分先ほど面倒くさくてVirtulaboxのバージョンをあげてしまったのが原因だと思います。
急がば回れとはこのことですね……

毎回手動でアップデートするのは、面倒なのでvagrant-vbguestというプラグインを入れます。
このプラグインはGuest Additionsが一致しないときに、自動でインストールしてくれるパッケージです。

```terminal
$ vagrant plugin install vagrant-vbguest
```
でインストールします。
その後、`vagrant up`などのコマンドを実行すると、自動でインストールされます。

私の場合はすでにupしていたのでreloadしました。

```terminal
$ vagrant reload
```

一致しているかは以下のコマンドで確認できます。
また、`vagrant vbguest --do install`でインストールも可能です。

```terminal
$ vagrant vbguest --status
$ vagrant vbguest --do install
```

# 参考

- http://alginplus.blogspot.com/2011/05/implementation-of-usb-20-controller-not.html
- https://blog.amedama.jp/entry/2015/08/19/204044
- https://www.task-notes.com/entry/20150714/1436842800
GPSの研究　その45

#概要
gpsを理解したかった。
arduinoでgpsシュミレータ作った。
u-centerに、流してみた。

#写真

![image](https://qiita-image-store.s3.amazonaws.com/0/18104/bf211b6b-f1db-a11e-30ea-1e27218ba943.png)


![CIMG2687.JPG](https://qiita-image-store.s3.amazonaws.com/0/18104/4bf2aff7-ede4-ddbe-5b94-a2f05c51b680.jpeg)

以上。
深層学習を用いたドローン監視

2017年に南カルフォルニア大学で発表された「深層学習を用いたドローン監視」という論文のまとめと、これはすごい！と思ったことを書きたいと思います。

##A Deep Learning Approach to Drone Monitoring 
Yueru Chen, Pranav Aggarwal, Jongmoo Choi, and C.-C. Jay Kuo 
University of Southern California, California, USA
Dec/2017
引用URL: https://arxiv.org/pdf/1712.00863.pdf

###動機
私はドローン測量を手がけるスタートアップで長期インターンに参画していた時、測量中にドローンをロストしてしまうという問題に何回も直面した。森林の奥地までチームを組んで測量をするが、山や木々に視界を邪魔され、小さいドローンは風景と同化し、遠くに飛ばされたドローンに固定されているカメラしか視界を確保できない。そのためドローンを木に衝突させてしまったりどこを飛んでいるのか確認できなかったりする。
　今後このような測量が主流になる上、配達、セキュリティ、農業、点検など多岐にわたる分野でドローンが活用され、違法に使われるドローンも増えていくと考えられる。膨大なドローンを全て人間の目で把握/監視するのは不可能なため、私は画像認識を応用してドローンの検知かつ追跡を可能にするシステムについて取り上げたこの論文を選んだ。

### 論文まとめ

当論文はドローン検知と追跡モジュールを搭載したドローン監視システムを提案している。ドローン監視における難題はドローンが写った画像が手に入りにくいことと、ドローンが背景に埋もれてしまうことである。しかし、このシステムはドローン単体の画像と風景を合成させて自動で画像を生成し、ビデオのフレーム画像の残差も利用し、画像をカサ増しすることでこの問題にアプローチしている。この方法により実世界の複雑な背景の中からドローンを追跡し続けることが可能である。

監視システムの学習の流れとして、①カサ増し作業も含め、学習用の写真を用意する。②2種類の異なるCNNのモデルを用意し、統合する。③2種類のモデルを訓練し、統合モデルの評価指数を設定して精度を検証する。

①まず学習させるための画像の絶対数を増やすために2種類の方法を試している。一つは、3Dレンダリングアルゴリズムと従来の画像生成技術を用いて、大量のドローン合成写真を自動で作り出すことである。カメラの角度/距離、光の強さなどを変えドローン単体の写真を用意する。また、背景画像も引き延ばしたりドローン配置位置をランダムに決める。その2つの画像をぼかしや影を付け加えて自然な合成写真にする。二つ目として、ビデオのフレームは1秒間に30~40ほどだが、直前の画像との相違に注目することで動いている物体のみの情報を抽出することである。これにより周りの静止した複雑な風景を取り除くことができる。

②ドローン監視システムは検知のみのモジュールと追跡のみのモジュールに分けられる。検知システムには基本的に静写真を用いて、高速RCNNという畳み込み深層学習で学習させる。追跡システムはCNNより層が少ないMulti-Domain Network (MDNet)を用いて、今のフレームから次のフレームのどの位置にドローンがいるか大方見当をつける。この学習器に連続する写真の色の残差を取った写真を訓練させることで、動いている物体に注目することができる。（これにより、ドローンをロストしても複雑な背景を無視して動いている物体のみに注目できるため、ドローンの再検出が早くなる。）

この2つのモジュールを統合した監視システムはドローン検出と追跡機能を初期化することの2つのタスクがある。始めにドローン検出により追跡するターゲットを決め、追跡を開始する。仮にロストした場合、追跡機能によりドローンの大方の位置はつかめているため、再びドローン検知を行い検出したら追跡機能を初期化する。この繰り返しによりドローンを常に監視し続けることが可能である。

③検出システムは合成写真を使わない場合と比べて11~16%ほどAUCスコアが上昇し、90%ほどの精度を出した。一方、追跡システムは評価指数としてフレーム1枚ずつに対し、IoU(実際のドローン範囲と検出した範囲の、重なっている範囲/合わせた範囲)を算出。それがある閾値以上だとその写真は正しく検出したとして1、それ以外は0として評価した。それらを全体のフレーム数で割ることで閾値に対して正解率のグラフを作ることができる。すると合成写真を使わない場合と比べて10％ほどスコアが上昇し、60~70%ほどの精度が出た。そして2つを統合したシステムは70%強の精度が出た。

### この論文ですごいと思ったこと

・ドローン監視/ロスト問題を検出と追尾を組み合わせたコンピュータビジョンの技術で解決しようと思ったこと。従来はドローンに搭載されているGPSや付属のカメラ情報、または監視の人手を増やすことでドローンの位置を把握していた。ドローン測量では気が生い茂る山間部では電波が届かなかったり、搭載カメラの死角でロスト/衝突という問題があった。しかしこの方法を用いれば画像認識技術で人間の目で見るよりも、正確にドローンを検出/追跡でき、ロストという不具合も見込んでいる。この技術は測量のみならず違法ドローン検出や人口密集地域上空で飛ぶドローンの監視など様々な分野で活躍が見込められるだろう。

・画像カサ増し方法。ドローンと背景の自然な自動合成技術を用いれば、インプット画像数が少ないことによる過学習を防ぐことができる。このカサ増し方法を用いて「機械の視界」の訓練もできるので、無人機が自動で操縦される時、危険の察知や目標物の検出に役立ちそうである。例えば、自動配達ドローンでは届け先の目印検知、自動運転では人や障害物の危険察知などである。

・ビデオシャッターの隣同士のフレーム画像の差異をとることで動いている物体のみに注目することができることである。風景を含む大量の静止情報を処理する必要がないので、周りの邪魔な情報を取り除くことでターゲットを検出/追いやすくできる。「動くもの」に注目し、ターゲットを追跡するシステムは野生動物の監視、天体観測などの自然環境から夜中の不審者検出などのセキュリティ面でも幅広く応用できるかもしれない。
VirtualBoxのバージョンをあげたら、ディレクトリが共有されなくなる問題解決

# kernel-develが問題
何らかの理由によりkernel-develに差異が発生し、VBoxGuestAdditionsのインストールに失敗してしまう。

私の環境では、以下のような感じだった。

```
$ yum list installed |grep kernel
kernel.x86_64                   2.6.32-358.23.2.el6               @C6.4-updates/6.4
kernel-devel.x86_64             2.6.32-358.23.2.el6.centos.plus   @/kernel-devel-2.6.32-358.23.2.el6.centos.plus.x86_64
kernel-firmware.noarch          2.6.32-358.23.2.el6               @C6.4-updates/6.4
kernel-headers.x86_64           2.6.32-358.23.2.el6               @C6.4-updates/6.4
```

# 以下の手順で、kernel-develを再インストール
1. アンイストール
1. rpmを取得
1. インストール
1. ゲストOS（CentOS）再起動

```
$ sudo yum remove kernel-devel
$ wget http://ftp.iij.ad.jp/pub/linux/centos-vault/6.4/centosplus/x86_64/Packages/kernel-devel-2.6.32-358.23.2.el6.centos.plus.x86_64.rpm
$ sudo yum install kernel-devel-2.6.32-358.23.2.el6.centos.plus.x86_64.rpm
```
Azure Blob Storageでパブリック公開されているコンテナーを出力する

Blob Storageのコンテナーには、3種類のアクセスポリシーがあります。

* プライベート（パブリック読み取りアクセスなし）
* BLOB（BLOBに限定したパブリック読み取りアクセス）
* コンテナー（コンテナーのBLOB一覧も列挙可能なパブリック読み取りアクセス）

「プライベート」以外のアクセスポリシーは、誰でもアクセスできるようになっているので気をつけたいところです。
自分が管理しているサブスクリプションで、想定外のパブリック公開Blobがないかチェックしたくてコマンドレット作りました。
動作はCloud Shellで試していますが、Azure CLI/PowerShellでサブスクリプションが認証されていれば動くと思います。

# Azure CLI
* Cloud Shell(Bash)を開いて実行します

```
for accountName in `az storage account list --query [].name -o tsv`
do
  for containerName in `az storage container list --account-name $accountName --query [].name -o tsv`
  do
    permitType=`az storage container show-permission --name $containerName --account-name $accountName -o tsv`
    if [ "$permitType" != "off" ]; then
      echo "acount-name: $accountName, container-name: $containerName, permission-type: $permitType"
    fi
  done
done
```

# Azure PowerShell
* Cloud Shell(PowerShell)を開いて実行します。

```
$allStorageAccount = Get-AzureRmStorageAccount
for ($i = 0; $i -lt $allStorageAccount.StorageAccountName.Count; $i++) {
  $containerInfo = Get-AzureRmStorageAccount -Name $allStorageAccount.StorageAccountName[$i] -ResourceGroupName $allStorageAccount.ResourceGroupName[$i]
  Get-AzureStorageContainer -Context $containerInfo.Context | Where-Object { $_.PublicAccess -ne 'Off' }
}
```
ionic ライフサイクル

# ライフサイクルイベントとは
ページが表示、非表示になるタイミングで発生するイベントのこと

# constructor
ライフサイクルイベントではない
DOM操作に関する実行は入れない
ー＞ここに書くと画面に反映されないかも...

## ionicのライフサイクル
### ionViewDidLoad
ロードされたときに実行
DOM要素、カスタムコンポーネントへのアクセス
### ionViewWillEnter
ページがアクティブになる直前に実行
nav.pop()で戻ったときは実行されない
イベントの登録やデータ取得に利用する
### ionViewDidEnter
ページがアクティブになったとき実行
nav.pop()で戻ったときも実行
データを常に最新にしたいときに利用する
### ionViewWillLeave
ページが非アクティブになる直前に実行
イベントを破棄するときに利用する
### ionViewDidLeave
ページが非アクティブになったときに実行
### ionViewWillUnload
ページが非アクティブになり、破棄される直前に実行
### ionViewCanEnter
ページを表示するか判定する
boolean型で返す(true: 表示、false:元のページに戻る)
### ionViewCanLeave
ページを離れるかどうか判定する
boolean型(true: ページを離れる、false: とどまる)
## Angularのライフサイクル
### ngOninit
コンポーネント生成時に実行
入力中のページ遷移の際にアラートを出したりするときに利用する
### ngOnDestroy
コンポーネントを破棄するときに実行
Python3でurllibを使う

# これはなに
Python3でHTTPアクセスをしたい場合は、urllibという組み込みライブラリを利用できます。
しかしながら、Python2に同名で互換性のないライブラリがあることや、
人間に扱い易いHTTPリクエストを実現するrequestsなどを勧められることがあるため、情報を集めづらくなっています。（当人調べ）

組み込みライブラリでHTTPリクエスト実現することは、簡易的なスクリプトやAWS LambdaなどとFunction as a Serviceでの利用を想定すると有効であるため、ターゲットを絞って使えるようにメモ書きを残します。

# Getリクエスト

```python
import os.path
import urllib.request
import urllib.parse

base_url = "https://www.google.co.jp/"
path = "search"
headers = {
    "Accept-Language": "ja_JP",
}
query = {
    "q": "urllib"
}

# os.pathを使ってURLを結合
url = os.path.join(base_url, path)

# クエリストリング
url_with_query = "{}?{}".format(url, urllib.parse.urlencode(query))

print(url_with_query)
req = urllib.request.Request(url_with_query, headers=headers)

# tryでエラーハンドリング
try:
    with urllib.request.urlopen(req) as res:
        body = res.read().decode("utf-8")
        print(body)

except urllib.error.HTTPError as e:
    # Status codeでエラーハンドリング
    if e.code >= 400:
        print(e.reason)
    else:
        raise e
```
Git & GitHubのコマンドメモ

#いつもやること

イメージとしては、addでローカル環境に一時保存、commitでローカル環境に本保存(一回やると変更するのが面倒)、pushでリモート環境に保存。

### 1. add

```
git add file もしくは git add --all
```

### 2. commit

```
git commit -m "Comment"
```

### 2.5. remote

前回と違うリポジトリにpushする場合はpush先の変更が必要。

```
git remote set-url origin repository-URL
```

### 3. push

```
git push
```

# ユーザーを変更する
会社とプライベートで使い分けたい時などに。

### 1. --globalオプションを付けて常に設定を適用させる

```
git config --global user.name "user_name"
git config --global user.email "user_address@gmail.com"
```

### 1'. 面倒なら、設定ファイルを直接書き換える

「C:\Users\User」にある「.gitconfig」をエディターで開くと、

```
[user]
	name = user_name
	email = user_address@gmail.com
[filter "lfs"]
	smudge = git-lfs smudge -- %f
	process = git-lfs filter-process
	required = true
	clean = git-lfs clean -- %f
```

のようになっているので、「name」と「email」の部分を書き換える。

```
[user]
	name = user_name_1
	email = user_address_1@gmail.com
;	name = user_name_2
;	email = user_address_2@gmail.com
```

のように、「;」もしくは「#」でコメントアウトできるのが便利かもしれない。


# コミットを削除する

### 1. 新しいコミットから削除

1つ目のコマンドは最新のコミットだけ、2つ目のコマンドはn個目のコミットまで削除。

```
git reset --soft head^ もしくは git reset --soft head~n (手元のファイルはそのまま)
git reset --head head^ もしくは git reset --hard head~n (手元のファイルも巻き戻す)
```

### 1'. 特定のコミットだけ削除

```
git rebase -i hash
```

### 2. -fオプションを付けて強制的にpushする

```
git push -f
```


# コメントを変更する

```
git commit --amend
```


# 過去の全てのAuthorとCommitterを変更する

後になってから間違いに気付いた時に。

```
git filter-branch -f --env-filter \
  "GIT_AUTHOR_NAME='user_name'; \
   GIT_AUTHOR_EMAIL='user_address@gmail.com'; \
   GIT_COMMITTER_NAME='user_name'; \
   GIT_COMMITTER_EMAIL='user_address@gmail.com';" \
  HEAD
```
PDFのページ番号を編集する

書籍をスキャンして作った PDF ファイルで，目次や前書きなどのページ番号の表記を変更し，元の書籍のページ番号と PDF ビューアーでのページ番号を揃える方法．

修正前の PDF ファイルは，Canon DR-C225W を使って Mac でスキャンしたものを想定しています．qpdf を使います．

たとえば，PDF の 1 枚目から 4 枚目のページ番号を i から iV までにして，5 枚目のページ番号を 1 にしたい時．

```bash
qpdf —pdf 元ファイル.pdf 作業ファイル.qdf
```
で，作業ファイルを作る．適当なテキストエディタで編集．viあたりがいいんじゃないかな．emacsだと重いかも．

```pdf
%% Original object ID: 2 0
1 0 obj
<<
  /Pages 3 0 R
  /Type /Catalog
>>
endobj
```

のような感じのところ，要するに `/Pages` の記述があるところに `/PageLabels` の記述を追加

```pdf

%% Original object ID: 2 0
1 0 obj
<<
  /Pages 3 0 R
  /PageLabels << /Nums [
      0 << /S /r >>
      4 << /S /D >>
    ] >>
  /Type /Catalog
>>
endobj
```
とする．ちなみにインデントは適当です．

`0 << /S /r >>` のところがページ番号の書式の設定で，数字 0 が PDF の何枚目か，`<< /S /r >>` が小文字のローマ数字，`<< /S /D >>` とするとアラビア数字を表すようです．詳しくは [W3C の PDF17: Specifying consistent page numbering for PDF documents](https://www.w3.org/TR/WCAG20-TECHS/PDF17.html#PDF17-ex2) を見ればよさそうです．

```bash
fix-pdf < 作業ファイル.qdf > 最終ファイル.pdf
```
でpdfに戻す

参考：https://superuser.com/questions/232553/how-to-change-internal-page-numbers-in-the-meta-data-of-a-pdf
Windows10のWSLを有効化するとWifiが無効化されるのを解決する

#はじめに
Ubuntu 16.04環境をMicrosoft Storeからインストールしてみたところ、Wifiが無効化されてしまう症状に悩まされたので、解決策を自分の備忘録として残しておきます。

#使用環境
Windows 10 Pro (10.0.17134 ビルド 17134)
Ubuntu 16.04 (Windows Storeからダウンロードして利用)

#症状
Windows Subsystem for Linux(WSL)を有効化すると、Wifiが全て無効になってしまう。
コントロールパネルから、WSLを無効化すると、再度Wifiが使えるようになるが、Ubuntuを立ち上げる度に手作業で無効化するのは避けたい。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/46402/dc4aa375-bbda-b692-c01b-71f764056eb8.png)

#解決方法
Windows PowerShellから、以下のように入力し、HYPER-Vをインストールする。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/46402/801f7c9f-ee56-7bd1-e0fc-f6dbf7a7c153.png)

再起動後、正常にインストールされると、"Windowsの機能の有効化または無効化"のダイアログに、Hyper-Vのチェックボックスが表示される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/46402/74e423c3-582b-b7b3-fe12-24efcbcd15b1.png)

Hyper-Vにチェックが入っており有効になっていれば、Windows Subsystem for Linuxを有効化しても、正常にWifiが動作するようになる。

#注意事項
Hyper-Vが有効になっていると、VMWare Playerや、VirtualBoxなどの仮想マシンが起動時にエラーになる。
これらを使う場合には、Hyper-Vのチェックを無効にする必要がある。
シェル — 最後に実行したコマンドを再実行する ( !! )

## 答え

タイトルの通り `!!` で可能


## なんと呼ぶ？

「ダブルバン」とか。

(和風が好きなら「にじゅうびっくり」でも良い)

## 例

現在時刻を表示する

```
$ date +%s
1535343779
```

次に `!!` で再実行する


```
$ !!
date +%s
1535343781
```

コマンドが再実行され、時刻が進んでいるのが分かる。

結果だけではなく、
「コマンド内容」と「結果」があわせて表示されようだ。

次に矢印キーなどでコマンド履歴を戻ると
`!!` ではなく、再実行後のコマンドが出てくるのが分かる

```
$ date +%s!
```

## 数指定

`!-数字` という記法で、何個前の履歴を再実行するかを選べる。

### 例

例として、まずは三個のコマンドを実行しておく

```
$ echo Alice
Alice
```

```
$ echo Bob
Bob
```

```
$ echo Carol
Carol
```

ここで二個前のコマンドを再実行する

```
$ !-2
echo Bob
Bob
```

もういちど「二個前のコマンド」を再実行する

ここでは、二個前に実行したのは `echo Carol` になる (繰り上がり)

```
$ !-2
echo Carol
Carol
```

## Versions

- sh 3.2
- bash 4.4
- Docker version 18.03.1-ce, build 9ee9f40
- Mac OS X High Sierra

## Ref

- [shell - How do I repeat the last command without using the arrow keys? - Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/147563/how-do-i-repeat-the-last-command-without-using-the-arrow-keys)
- [linux - Start a line in bash script with !! (double bang) - Stack Overflow](https://stackoverflow.com/questions/42193396/start-a-line-in-bash-script-with-double-bang)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->