OmniAICreator/Qiita-1.07M huggingface dataset:
シンボル(Symbol)って何？

symbolicなsymbol。:scream:
# tl;dr
+ **symbol** はES6で導入された新しいプリミティブ。
+ **symbol(** *[description]* **)** で作成。
+ 作成するたびにまったく新しいSymbolを返す。

# シンボルとは？
> <details><summary>**symbol**は、ユニーク[^1] で不変なデータ型で、オブジェクトのプロパティ識別子として使われたりします。</summary>symbolオブジェクトは、Symbolプリミティブデータ型をラップした暗黙的なオブジェクトです。</details>
[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol)

一度作成した **symbol** はそれ自身とのみ等しい。
ということは、
まったく同じ **symbol** は二度と作ることはできない。

## 作成方法
```javascript
const sym1 = Symbol();

const sym2 = Symbol("デバッグ用の説明。これは、Symbol自体には関係がない。");
```

`new` 演算子を用いた構文はエラーを投げます。

```javascript
new Symbol(); // TypeError
new Symbol("イエーイ"); // TypeError
```

下のコードでは、すべて `false` が返されます。

```javascript
Symbol() === Symbol(); // false
Symbol("abc") === Symbol("abc"); // false 
```

### オブジェクトのキーとして利用する :key:
```javascript
let obj = {};
const sym = Symbol("obj のキー");
obj[sym] = "xyz";

console.log(obj[sym]); // "xyz"
```

**symbol** はオブジェクトのキーとして利用することができる。
これを利用すれば、

+ キーが被ることがない。
+ ライブラリ・フレームワークなどとキーでの衝突を防げる (そのような状況になったことはないが)。
+ キーを文字列で指定した場合に比べて、改変などされるリスクが減る (**決してなくなるわけではない** [^2])。

## <code><strong>Symbol(</strong> <i>key</i> <strong>)</strong></code> の利用

> <details>
<summary>`Symbol()` と対照的に、`Symbol.for()` 関数はグローバルシンボルレジストリリスト内で利用可能なシンボルを生成します。</summary>`Symbol.for()` は必ずしもすべての呼び出しで新しいシンボルを生成するわけでなく、引数で与えられた `key` をもつシンボルがレジストリ内にすでに存在しているかどうか最初に調べます。存在している場合は、そのシンボルが返されます。引数で与えられたキーをもつシンボルが見つからない場合、 `Symbol.for()` は新しいグローバルシンボルを生成します。
</details>
[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for#%E8%AA%AC%E6%98%8E](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for#%E8%AA%AC%E6%98%8E)

つまり、

+ 同じ *key* を指定すれば、 同じ **Symbol** を生成できるってこと (なはず。。。)

```javascript
let obj = {};
const sym1 = Symbol();
const sym2 = Symbol("debug");
const sym3 = Symbol.for("key");

obj[sym1] = "lorem";
obj[sym2] = "ipsum";
obj[sym3] = "dolor";

// 下記は undefined を返す
console.log(obj[Symbol()]);
console.log(obj[Symbol("debug")]);
console.log(obj[Symbol.for("debug")]);

// 下記は セットした値を返す
console.log(obj[Symbol.for("key")]); // "dolor"
```

## <code><strong>Symbol.keyFor(</strong> <i>sym</i> <strong>)</strong></code> の利用

> 引数で与えられたシンボルに対してグローバルシンボルレジストリから共有シンボルキーを取得します。
[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/keyFor](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/keyFor)

つまり、

+ `Symbol.for( key )` で作成した *symbol* から また `key` を探せる

という解釈？？？？

```javascript
const sym1 = Symbol();
const sym2 = Symbol("debug");
const sym3 = Symbol.for("key");

console.log(Symbol.keyFor(sym1)); // undefined
console.log(Symbol.keyFor(sym2)); // undefined
console.log(Symbol.keyFor(sym3)); // "key"
```

# 

# 結論
+ だいたいはつかめた。
+ 使うタイミングが私にはまだないかも。(あったら教えてください)
+ まだでも、それ自体がsymbolicではっきりとわからない。

[^1]: **唯一の**, **たった一つの**, **ほかにない**, **一意の** という意味。決して、変わったとかいう意味ではない。
[^2]: <code><strong>Object.getOwnPropertySymbols(<strong> <i>obj</i> <strong>)</strong></code> で指定されたシンボルの配列を取得できるため。
at coder beginner 035

B
無限に広い二次元グリッドの原点 (0,0) に高橋君と 1 台のドローンがいます。このドローンは文字列が与えられた時、文字列の先頭から末尾までのそれぞれの文字を 1 つの命令と解釈して順に実行します。命令は以下の 4 種類です。
L 現在のドローンの位置を (x,y) として (x−1,y) に移動する
R 現在のドローンの位置を (x,y) として (x+1,y) に移動する
U 現在のドローンの位置を (x,y) として (x,y+1) に移動する
D 現在のドローンの位置を (x,y) として (x,y−1) に移動する
今、ドローンに何らかの命令が与えられ、どこかへと移動しました。高橋君はドローンに送られた命令を表す文字列である S を手に入れたものの、いくつかの箇所は破損し?になり分からなくなってしまいました。ただし、?が元々はL、R、U、Dのいずれかの文字だったことが分かっています。
ドローンと高橋君の距離はドローンの位置を (x,y) としてマンハッタン距離 |x|+|y| で表されます。求める値の種類を表す整数 T が与えられるので、移動を終えたあとのドローンと高橋君の距離としてありうる値のうち、 T=1 ならば最大値を、 T=2 ならば最小値を求めてください

新鮮な感じ。

```
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
int main() {
	string S;
	int T;
	cin >> S >> T;
	int x = 0;
	int y = 0;
	int count = 0;
	for (int i = 0; i < S.size(); ++i) {
		if (S[i] == 'L')
			x++;
		else if (S[i] == 'R')
			x--;
		else if (S[i] == 'U')
			y++;
		else if (S[i] == 'D')
			y--;
		else if (S[i] == '?')
			count++;
	}
	int z = abs(x) + abs(y);
	if (T == 1) {
		cout << z + count << endl;
	}
	else {
		if (z > count) {
			cout << z - count << endl;
		}
		else {
			cout << S.size() % 2 << endl;
		}
	}
	return 0;
}
```
C

```
#include <iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int INF = 1e9 + 7;
int main() {
	int N, Q;
	cin >> N >> Q;
	vector<int>flag(N, 0);
	for (int i = 0; i < Q; ++i) {
		int a, b;
		cin >> a >> b;
		a--; b--;
		for (int j = a; j <= b; ++j) {
			flag.at(j)++;
		}
	}
	for (int i = 0; i < N; ++i) {
		if (flag.at(i) % 2 == 0) {
			cout << 0;
		}
		else {
			cout << 1;
		}
	}
	cout << endl;
	return 0;
}
```
TLE

いもすを使おう

```
#include <iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int INF = 1e9 + 7;
int main() {
	int N, Q;
	cin >> N >> Q;
	vector<int>flag(N+1, 0);
	for (int i = 0; i < Q; ++i) {
		int a, b;
		cin >> a >> b;
		a--; b--;
		flag.at(a)++;
		flag.at(b + 1)--;
	}
	for (int i = 0; i < N; ++i) {
		if (0 < i)flag[i] += flag[i - 1];
	}
	for (int i = 0; i < N; ++i) {
		if (flag.at(i) % 2 == 0) {
			cout << 0;
		}
		else {
			cout << 1;
		}
	}
	cout << endl;
	return 0;
}
```
いもすは強い
【学習1日目】node.jsによる画面遷移

```js:sample.js

var http = require('http');
var fs = require('fs');

var server = http.createServer(function(req,res) {var target = '';
 switch (req.url){
   case '/':
   case '/index': target = './index.html';
    break;
   case '/next': target = './next.html';
   　break;
   default:
   　res.writeHead(404,{'Content-Type':'text/plain'});
   　res.end('bad request');
   return;
 }

 fs.readFile(target,'utf-8',function(err,data){
   res.writeHead(200,{'Content-Type':'text/html'});
   res.write(data);
   res.end();
 });
});

server.listen(1234);

console.log('サーバを起動しました');

```

```html:next.html
<!DOCTYPE html>
<html>
<head>
<meta charset ="utf-8">
<title> sample </title>
</head>
<body>
<h1> 次のページ </h1>
<p> 最初のページを押して見てね！ </p>
<a href ="/index"> 最初のページ　へ </a>
</body>
</html>

```

```html:index.html
<!DOCTYPE html>
<html>
<head>
<meta charset ="utf-8">
<title> sample </title>
</head>
<body>
<h1> 初心者からの離脱 </h1>
<p> 次のページを押して見てね！ </p>
<a href ="/next"> 次のページ へ </a>
</body>
</html>


```

・以下追記
sample.jsに無駄があったので修正。同じファイルをなんども読み込んでいた。

```js:sample.js
var http = require('http');
var fs = require('fs');

var indexPage = fs.readFileSync('./ index. html', 'utf-8');
var nextPage = fs.readFileSync('./ next. html', 'utf-8');



var server = http.createServer(function(req,res) {var target = '';
 switch (req.url){
   case '/':
   case '/index':
   　target = indexPage;
     break;
   case '/next':
     target = nextPage;
    　break;
   default:
   　res.writeHead(404,{'Content-Type':'text/plain'});
   　res.end('bad request');
   return;
 }

 fs.readFile(target,'utf-8',function(err,data){
   res.writeHead(200,{'Content-Type':'text/html'});
   res.write(data);
   res.end();
 });
});

server.listen(1234);

console.log('サーバを起動しました');


```
[Let's encrypt]let's encryptでSSL認証書を作り直したらサーバがこけるようになった。。。

## 問題
ドメインの変更をする必要があり、SSL証明書を再度作成した。
ここで、サーバがこけるようになった


## 原因
Appacheのssl.confの編集を忘れていた。
	+ 削除した古いドメインでの暗号鍵ファイルを参照していた。
		- 古い暗号鍵は削除していたためサーバ起動時にエラーが起こっていた
		
## 解決策
以下のコマンドをうってファイルのパスを修正した。
sudo vim /etc/httpd/conf.d/ssl.conf


## 参考
[SSL認証書の作り直しの参考](https://def-4.com/lets-encrypt-multi-domains/)
javascriptでsleepを実現する方法(実際にはsetTimoutを利用)

Javascriptでsleepを実装したいことがあるが、sleepは存在しない為、何らかの方法で実装する必要がある。
sleepを実現するには、現在時刻やループなどを組み合わせて実現したりと幾つか方法があるが、今回は一番容易な「setTimeout」の利用方法を以下に記載する。

```javascript:setTimeoutの記述例
  setTimeout(
    function () {
      console.log("アラートを表示したました。");
      alert("3秒経ったのでアラートを表示しました。");
    }, 
    "3000"
  );
```
上記は、3秒後にコンソールにログを出力してアラートを画面に表示している。
この「console.log」や「alert」を呼び出したいメソッドに変えれば、sleepを実現することが出来る。

以下は、「setTimeout」を利用する際の全体のプログラムである。

```javascript:setTimeoutの利用例
window.onload = function () {
  var obj = document.querySelector("body");
  setTimeout(
    function () {
      obj.setAttribute("style", "display:none")
    },
    "10000"
  );
};
```
上記は、画面を描画してから10秒後に、表示内容を削除(非表示)するロジックである。
Pythonの例外型やスタックトレースを確認する

# 概要
sysモジュールの `exc_info` メソッドを使うと、例外オブジェクトやスタックトレースオブジェクトのインスタンスを受け取ることができる

## サンプルコード
```python
import sys
import traceback

try:
    1/0
except Exception:
    a, b, c = sys.exc_info()  # type, value, traceback
    print('=========================================================')
    print(type(a))
    print(a)
    print('=========================================================')
    print(type(b))
    print(b)
    print('=========================================================')
    print(type(c))
    print(c)
    print('=========================================================')
    traceback.print_tb(c)
    print('=========================================================')
```

## 実行結果
```
=========================================================
<class 'type'>
<class 'ZeroDivisionError'>
=========================================================
<class 'ZeroDivisionError'>
division by zero
=========================================================
<class 'traceback'>
<traceback object at 0x1099f60c8>
=========================================================
  File "test.py", line 5, in <module>
    1/0
=========================================================
```
AWSの画像認識API  Rekognitionをちょっと試してみた(awsコマンドとPython版)

awsのS3はこんなかんじです。
![Screen Shot 2018-09-23 at 16.45.12.png](https://qiita-image-store.s3.amazonaws.com/0/48316/52140875-f9e5-862a-dd54-84211e3502f8.png)

では画像認識してみよう。

## 準備
・awsコマンドが打てるようにaws-shellをインストール
・python上でaws接続できるようにboto3をインストール

```
pip install aws-shell
pip install boto3
```

## 実行

### awsコマンドの場合

```
aws rekognition detect-labels --image '{"S3Object":{"Bucket":"hogeeeeee","Name":"2018-08-29 19.46.23.jpg"}}'
```

### python実行の場合
```
import boto3

rekognition = boto3.client("rekognition", "us-east-1")
bucket = "hogeeeeee"
key = "2018-08-29 19.46.23.jpg"

response = rekognition.detect_labels(
		Image={
			"S3Object": {
				"Bucket": bucket,
				"Name": key,
			}
		}
	)

print(response)
```

以上。どっちもやってることは一緒。

## 出力結果

```
{
    "Labels": [
        {
            "Name": "Bbq",
            "Confidence": 98.98237609863281
        },
        {
            "Name": "Food",
            "Confidence": 98.98237609863281
        },
        {
            "Name": "Brick",
            "Confidence": 65.28954315185547
        },
        {
            "Name": "Lighting",
            "Confidence": 53.96083068847656
        }
    ]
}

```

出力結果からなんの画像かわかる？


・
・
・


正解はこちら。
![2018-08-29 19.46.23.jpg](https://qiita-image-store.s3.amazonaws.com/0/48316/00fd3d89-6255-6d8f-cdf6-3ec421c83e70.jpeg)


厚切り牛タンであることは検知できなかった。

飯テロでした。
組み込みの現場からwebアプリ開発に放り込まれて学んだgit及びgithubで気をつけること

#以前と今
###過去の組み込みの現場で使っていたsource管理ツール
- [winCVS ごった煮](https://www.softantenna.com/softwares/3330-wincvs-1-3-sjis)
- [TortoiseSVN](https://tortoisesvn.net/docs/nightly/TortoiseSVN_ja/index.html)

###今のwebアプリ開発の現場のsource管理ツール
- [git](https://git-scm.com/)
- [github](https://github.com/)

CVS、SVNなどの集中型とgitのような分散型バージョン保存システムの違いはここでは取り上げません。

現場に入る前にgitについてはここをやりました。
[LearnGitBranching](https://learngitbranching.js.org/)

###その他環境
- Editor
[VSCode](https://code.visualstudio.com/)
- Gitクライアント
[GitKraken](https://www.gitkraken.com/)

#実際のwebアプリ開発の現場で気をつけていたこと
##Branchを切り間違えない
VSCodeを使っていると、間違えてdevelopに戻らずに今いるBranchからBranchを切ってしまったことがある。
その際は現時点の作業を一旦stashして退避、developに戻って新たにBranchを切り直して、新たなBranchでstash popして作業を続行する。
慣れないうちは難しいことをせずに確実に基本的なことをやっていく。
じゃないと、「あれ？今のBranchでこんなのcommitしてないのになんで紛れ込んでるの？」とかなってしまう。

##commitはレビュー担当者に分かりやすい単位で行う
自分もやってしまったことがあるが、たくさんのファイルを一気にcommit、pushしてしまうと、レビュー担当者にとって非常に見難いプルリクエストとなってしまう。
例えばCRUDのUpdateを追加するなら、controllerとそのテストをコミット、serializerとそのテストをコミット、という風に変更したファイルと対になるテストをコミットしていくとレビュー担当者が流れを追いやすくなる。

##Gitクライアントツールを有効活用する
gitというとCUI上でやり繰りするのが通みたいな感じがあるが、この世にはSourceTreeやGitKrakenみたいなGUIになっており、見て分かりやすいツールがある。
GUI上でポチポチするだけでCherry-pickやpullできるようになっているので、わざわざCUI上でコマンド打ってトラブって消耗するよりは、便利なツール使ってスムーズに開発を進めたほうがよいと考える。



※他、思い出し次第追記
zoomusを使いたい

# zoomusとは
zoomのapi?
# zoomとは
これ
https://zoom.us/jp-jp/meetings.html
Skypeみたいに通話できるツール

# やりたいこと(できていない)
zoomusのapiを使ってzoomを利用(誰かと通話)すること

# zoomのドキュメント
https://devdocs.zoom.us/docs


# 言語
Ruby
理由：とあるサービスをRailsで作る予定だから

# GitHubにあったライブラリ
https://github.com/mllocs/zoomus

# おそらくやること
・JWTでトークンを取得
・トークンからuser_idを取得？
・user_idlから通話？


# やったこと

http://r9.hateblo.jp/entry/2018/01/30/081534
これを見る限りは
・JWTでトークンを取得
・トークンからuser_idを取得？
・user_idlから通話？
なんだけどなぁ。。。同じことをrubyでどうやってできるのだろうか

# JWT
Rubyでjwtを利用する
https://blog.shimar.me/2017/02/10/ruby-jwt.html

## zoom APIでの利用はHS256
https://devdocs.zoom.us/docs/jwt
>Warning
The Zoom API uses HS256. Use of other algorithms may produce unexpected results.

## Claimはissとexp
- iss:zoom APIキー
- exp :有効期限:現在の時刻から+整数

>Note
The expiration time (exp) can be defined in a numeric date time format.

expは日付形式

https://github.com/jwt/ruby-jwt
これのpayloadでClaimを設定すればOKっぽい=> ~~JWTはクリアできそう~~
以下の内容でJWTは生成できた

```ruby
module ApplicationHelper
	class TS_Zoom
		def GenerateJWT
			payload = { 
				iss: 'api_key', #api_key
				exp: Time.now.to_i + 4 * 3600
			}
			secret  = 'secret_key' #secret_key
			token = JWT.encode payload, secret, 'HS256'
			return token
		end
	end
end
```

~~しかし、ターミナルで以下を打っても`(23) Failed writing body` と出る~~
~~`curl -H 'Authorization: Bearer JWTの文字列' https://api.zoom.us/v2/users | jq .`~~
ターミナルで`curl -H 'Authorization: Bearer JWTの文字列' https://api.zoom.us/v2/users`を打てばユーザ情報がでる

あとは、リクエストをRubyでどう扱うか、、、
https://docs.ruby-lang.org/ja/latest/class/Net=3a=3aHTTP.html
が使えるようです。
POSTの使い方はこちらかな
https://qiita.com/seisonshi/items/c23c0154c45ccbfa9999

以下のコード書いて実行してみた。

```ruby
module ApplicationHelper
	class TS_Zoom
		def initialize
			@api_key = "aaa"
			@secret  = "bbb"
			@user_id = "ccc"
			@jwt = "ddd"
			@meeting_url = "eee"
		end
		def GenerateJWT
			payload = { 
				iss: @api_key,
				exp: Time.now.to_i + 4 * 36000
			}
			token = JWT.encode payload, @secret, 'HS256'
			return token
		end

		def GetUserData(_token)
			uri = URI.parse("https://api.zoom.us/v2/users")
			request = Net::HTTP::Get.new(uri)
			request["Authorization"] = "Bearer "+_token
			req_options = {
				use_ssl: uri.scheme == "https",
			}
			response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
				http.request(request)
			end
			result = JSON.parse(response.body)
			return result["users"][0]["id"].to_s
		end

		def GetMeetingURL
			@jwt = self.GenerateJWT
			@user_id = self.GetUserData(@jwt)
			@meeting_url = "https://api.zoom.us/v2/users/#{@user_id}/meetings"

		    uri = URI.parse(@meeting_url)
		    http = Net::HTTP.new(uri.host, uri.port)

		    http.use_ssl = true
		    http.verify_mode = OpenSSL::SSL::VERIFY_NONE

		    req = Net::HTTP::Post.new(uri.path)
			req["Authorization"] = "Bearer #{@jwt}"
			aa = "Bearer #{@jwt}"
			puts aa
			req["Content-Type"] = "application/json"
		    req.body = {
		    	"type":1,
		    	}.to_json
		    res = http.request(req)
		    puts res.class
		    puts res.code
		    puts res.body
		    return res
		end
	end
end
```

結果
ホストのURLとJoinのURLが表示されアクセスすると通話成功！
PNGファイル圧縮のススメ - PNGGauntlet

PC再セットアップの際に毎回あれこれ探し回ったりするので、お気に入りのツールを備忘も兼ねて紹介しておこうと思います。

# PNGGauntlet
今回紹介するのは、PNGGauntlet で、PNG画像を圧縮するためのソフトウェア(GUI)です。
最終更新は少し古いのですが、Windows10でも問題なく動作しています。
インターネット上のサービスとして同種のものもありますが、これはインストールタイプとなります。

最近ではディスク容量も増え、あまりファイルサイズを気にしなくなってきたとはいえ、ホームページの画像やここQiitaに載せる画像など、インターネット上の画像ファイルは小さいにこしたことはありません。
PNGGauntletの圧縮率は66%前後で、高い場合だと50%を超える場合もあります。

![PNGGauntlet_SC1.png](https://qiita-image-store.s3.amazonaws.com/0/272546/2067913e-f887-8113-6c8b-072e9e87c4be.png)

基本的な使い方は簡単で、圧縮したいファイルをドラッグ＆ドロップしてOptimize!するだけ！

![PNGGauntlet_SC2.png](https://qiita-image-store.s3.amazonaws.com/0/272546/8b4ea31a-c386-8e26-63c2-26cc6e1ddf8a.png)

上記はGIMPで出力したPNGファイルをPNGGauntletで圧縮した時のものです。
オプションなどもありますが、初期設定で問題ないと思います。

# ダウンロード
ダウンロードは下記からできます。
[https://pnggauntlet.com/](https://pnggauntlet.com/)
LambdaでSlackBot作って学んだこと 

AWS LambdaでSlackBot作ってみました。
詰まったことやその対処法を共有します。

#### ０．記事の要約３行で
・Lambdaは処理を複数回実行する場合がある
・だから、Lambdaを使う場合は冪等性を考慮した設計を行う
・Slackメッセージを処理する場合は、event_idでチェックする

#### １．作ったもの
SlackからJIRAに課題投稿するBotを作りました。
![JIRA-PON.jpg](https://qiita-image-store.s3.amazonaws.com/0/174816/ca2c0eda-967f-4297-aa0f-dd3cd9cb85d8.jpeg)


Botにメンションメッセージを送ると、
メッセージを分解して、タイトルと説明文をJIRAに投稿してくれます。
メール内容をぱっと課題登録したいときとかに便利です。

仕組は以下です。
![JIRA-PON概要図.jpg](https://qiita-image-store.s3.amazonaws.com/0/174816/366d4269-8b7c-54c4-6933-18d0a5985611.jpeg)


Lambdaでメッセージを受けたら、そのままJIRA APIをコールして、
JIRAに課題を投稿します。
完了したらSlackAPIでメッセージを返します。

#### ２．詰まったこと
たまにBotが同じ課題を２つ登録することがありました。
調べてみると1回のSlackメッセージを2回処理していました。
どうやらLambdaはたまに内部で処理エラーを起こして、再度処理を実行する仕組みのようです。
以下の記事がとても参考になりました。
https://dev.classmethod.jp/cloud/aws/lambda-idempotency/

Lambdaを使う際は「再処理されても同じ結果になる実装」すなわち「冪等性」の考慮が重要とのこと！

#### ３．解決方法
Slackメッセージ固有のID(event_id)をチェックする仕組みを導入。
DynamoDBにIDを保存して、LambdaではまずIDをDynamoDBのデータと突合せチェックして、同じIDじゃなければDyanamoDBに登録して処理継続するようにしました。
![JIRA-PON概要図2.jpg](https://qiita-image-store.s3.amazonaws.com/0/174816/4f5561e9-c3ae-3c66-d229-1832803a2335.jpeg)


DynamoDBは、NoSQLのDBでAWSからボタン数クリックでテーブルが作れて便利ですね。LambdaからAPI経由でデータ登録/参照も容易です。

#### ４．おわりに
今回はBotKitを使わずに、Lambdaで実装しました。
サーバレスなので無料(月100万回コールまで)＋サーバ準備手間不要なのが魅力的ですね。
次に作るときはSQSを使ってみようと思います。
使ってみてわかった問題もあるのでどんどん共有していきます！
より良い実装方法などいろいろ教えてくださると幸いです^^
at coder beginner 034

B
10の9乗 人の人がいます。人には 1 から 10の9乗 までの番号がついています。 

1 番と 2 番の人、3 番と 4 番の人、5 番と 6 番の人、…　がペアになりました。 

n 番の人とペアになった人の番号を求めてください。 

```
#include<iostream>
using namespace std;
int main() {
	int n;
	cin >> n;
	if (n % 2 == 1)
		cout << n + 1 << endl;
	else
		cout << n - 1 << endl;
	return 0;
}
```

C


```
#include <iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int INF = 1e9 + 7;
int main() {
	int W, H;
	cin >> W >> H;
	map<pii, ll>dp;
	for (int i = 1; i <= H; ++i) {
		dp[{i, 0}] = 1;
	}
	for (int i = 1; i <= W; ++i) {
		dp[{0, i}] = 1;
	}
	for (int i = 0; i <= H; ++i) {
		for (int j = 1; j <= W; ++j) {
			dp[{i + 1, j}] = (dp[{i, j}] + dp[{i + 1, j - 1}]) % INF;
		}
	}
	cout << dp[{H-1, W-1}] << endl;
	return 0;
}
```
動的計画法。TLE

数学チックに解く必要があるっぽい。

フェルマーの小定理：ｐを素数、aをpと互いに素な整数とするとき、以下の等式が成り立つ。

a**(p-1)と１は等しい（mod p)

帰納法などで証明できる。

変形すると　a**(p-2)とa**(-1)は等しい(mod p)
これを利用して、Aで割りたい時はAのM-2乗で掛ければよい。

aのb乗をpで割った余りを計算する関数を考える。
b==0の時、return 1;
bが偶数の時、int d=calc(a,b/2,p);
            return (d*d)%p;とすれば良い
bが奇数の時、return (a*calc(a,b-1,p))%p;とすれば良い

```
#include <iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int INF = 1e9 + 7;
ll calc(ll x, ll n, ll mod) {
	if (n == 0)return 1;
	if (n % 2 == 0) {
		ll d = calc(x, n / 2, mod);
		return (d * d)%mod;
	}
	if (n % 2 == 1) {
		return (x*calc(x, n - 1, mod)) % mod;
	}
}//xのn乗をmodで割った余り
int main() {
	int W, H;
	cin >> W >> H;
	W--; H--;
	int exc[200010];
	exc[1] = 1;
	for (int i = 2; i < 200010; ++i) {
		exc[i] = (exc[i - 1] * i) % INF;
	}
	int ans = exc[W + H];
	//a^(p-2)=a^(-1)(mod p)
	ans = (ans*calc(exc[W], INF - 2, INF)) % INF;
	ans = (ans*calc(exc[H], INF - 2, INF)) % INF;
	cout << ans << endl;
	return 0;
}
```
なぜかWAくらうどこがちがうんやろ
インフラをオートレビューしたい！！（terraform）

## 前回までの流れ
以前の記事でひとまずローカルで回せるプログラムはできました。
[terraformをパースして自動で命名規則等のアラートを出したい！](https://qiita.com/ys_tydy/items/479a212a8e00864e33b1)
今回はレビューの設定を書くyamlを綺麗にしていこうと思います！！


## どのようなレビューにしたいか
テストは主に以下の二つ（否定形も含む）

- 存在チェック
    - ＊＊が存在しているか
- 内容チェック
    - ＊＊の値が＊＊か
    - ＊＊の値が特定の正規表現にあっているか

そしてそれらが条件で繋げられるようにしたい
（例：policy_documentの名前が `.*_secret` の時に `condition` が存在しているかどうか）

## 実際のyamlの形式

```yaml:s3.yaml
aws_s3_bucket:
-
  title: description_checker
  description: simple existance checker
  mode: existance
  key: description
-
  title: private_checker
  description: simple value checker
  mode: value
  key: acl
  value: private
-
  title: bucket_checker
  description: simple value regex checker
  mode: value
  key: bucket
  value: .*-tf-review-bucket.*
-
  title: tag_checker
  description: nested value checker
  mode: nested
  key: tags
  nest:
    -
      title: name_checker
      description: nested value checker
      mode: value
      key: Name
      value: .*-tf-review-bucket.*
    -
      title: env_checker
      description: nested value checker
      mode: value
      key: Env
      value: (dev|stg|prd)
-
  title: if_checker
  mode: if
  key: logging
  nest:
    title: name_checker
    mode: existance
    key: lifecycle_rule
```

## terraformのコードは `docker run` のマウントで設定
[tf_auto_reviewer](https://github.com/ys-tydy/tf_auto_reviewer/tree/v0.0.1)
以下のコマンドで実行することでテスト対象を設定できるように変更しました。
```docker run -v `pwd`/${TF_ROOT_PATH}:/tmp/terraform```
これであとはciで動的に設定できれば簡単なテストは実行できそう



## 今後やりたきこと
ログも綺麗にしてかなりいい感じになってきたので、
次は実際のデプロイフローに組み込みたい。。。

- yamlが否定形に対応できるように変更
- globがなぜか再帰的に見てくれないところを直す
- jenkinsで自動的にreviewしてくれるようにする
Python Bottle Hello World Bootstrap4

### 携帯電話からいろいろするためのHello World
### (所要時間30分)
### Stupid Phone用にCSSをできるだけ書かないようにするために基礎
+ ディレクトリー配置
+ プログラムソースの下にstatic/viewsフォルダを配置する。
+ static フォルダには、**[bootstrap4](http://getbootstrap.com/docs/4.1/getting-started/contents/#css-files)**からダウンロードしたjs/cssファイルを配置する。
+ favicon.png/favicon.icoは、static直下に配置する
+ Stupid Phoneの起動ICONにするために必要 
+ viewsの配下には、layout.tpl/index.tplを配置する。

```
BottleHelloWorld.py
├─static
│  │  favicon.ico
│  │  favicon.png
│  ├─css
│  │      bootstrap-grid.css
│  │      bootstrap-grid.css.map
│  │      bootstrap-grid.min.css
│  │      bootstrap-grid.min.css.map
│  │      bootstrap-reboot.css
│  │      bootstrap-reboot.css.map
│  │      bootstrap-reboot.min.css
│  │      bootstrap-reboot.min.css.map
│  │      bootstrap.css
│  │      bootstrap.css.map
│  │      bootstrap.min.css
│  │      bootstrap.min.css.map
│  └─js
│          bootstrap.bundle.js
│          bootstrap.bundle.js.map
│          bootstrap.bundle.min.js
│          bootstrap.bundle.min.js.map
│          bootstrap.js
│          bootstrap.js.map
│          bootstrap.min.js
│          bootstrap.min.js.map
│          jquery-3.3.1.min.js
│          popper.min.js
└─views
    │  index.tpl
    │  layout.tpl
```


```BottleHelloWorld.py
from bottle import *
@route('/')
@view('index.tpl')
def home():
    return dict()
@route('/static/<file_path:path>')
def static(file_path):
    return static_file(file_path, root='./static')
run(host="192.168.1.10",port=911,debug=True)
```

```index.tpl
% rebase('layout.tpl', title='Home Page')
<div class="jumbotron"><h1>Hello World</h1></div>
```
{{titl}}に上記で指定したHome pageが挿入される
{{!base}}にindex.tplが挿入される
{{}}に囲まれた中は、変数として扱われhtmlが生成される


```layout.tpl
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }}</title>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet" />
	<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
	<link rel="apple-touch-icon" href="/static/favicon.png" />
	<script src="/static/js/jquery-3.3.1.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/popper.min.js"></script>
</head>
<body>
<div class="container">
{{!base}}
</div>
</body>
</html>
```
「Stupid Phone」から http://192.168.1.10:911 アクセスする。
![20180923_161120.png](https://qiita-image-store.s3.amazonaws.com/0/274715/a0f19ec0-2e92-4a68-56d3-00b323b7abe4.png)
[WordPress] 記事一覧には表示されるのに、記事本文が表示されない。。。

### 問題 
記事一覧には表示されるが選択した記事ページが表示されない

### 環境
+ Webサーバ linux (Aws ec2)
+ wordpress : 4.9.8
	- wooCommerceなど商業サイト用のプラグインを導入

### 原因 
* 記事のパーマリンクに日本語が混ざっているのが原因だった。
	- plguinを全て停止したり、テーマを変えても同じなのでwordpressの仕様？
	
	
### 解決策 : 
* 記事のパーマリンクに日本語がはいらないようにパーマリンク設定を変更
	- カスタム設定から基本設定に修正
		+ 基本設定ではpage_idでパーマリンクを張っているため解決された！
mac でパスワード付き zip を簡単に作る方法

mac でパスワード付きの zip ファイルを作るのは面倒なイメージがあったのですが、新しく簡単な方法を知ったのでメモしておきます。

# 2つの方法

方法は２つあります。すでに存在する zip ファイルを暗号化する方法と、 zip 圧縮時に暗号化する方法です。

## 既存の zip ファイルを暗号化する方法

すでにパスワードを付与したい（暗号化したい） zip ファイルがある場合は、 `zipcloak` コマンドを使用します。
OS X Leopard 以降で使用できるみたいです。

```
$ zipcloak [zipファイルへのパス]
```

実行するとパスワードの入力が求められます。
完了すると指定した zip ファイルそのものが暗号化されたものに置き換わっています。

## 圧縮時に暗号化する方法

圧縮時に暗号化を行うこともできます。
この場合は、 zip 圧縮に `zip` コマンドを `-e` オプションを付与して使用します。

```
$ zip -e [出力ファイル名] [暗号化したいファイル]
```

または、フォルダごと zip 圧縮する場合は

```
$ zip -r -e [出力ファイル名] [暗号化したいディレクトリ]
```

を実行します。
実行するとパスワードの入力が求められ、ここで入力したパスワードで暗号化されます。

# 参照

http://www.atmarkit.co.jp/ait/articles/1511/20/news027.html
at coder beginner 033

B
N 個の町が合併し、1 つの新しい市になることになりました。合併前の i(1≦i≦N) 番目の町は名称が Si で、人口が Pi 人です。 新しい市の名称を、以下のように決めようとしています。
N 個の町の人口の合計の過半数以上の人口を有する町が存在するならば、新しい市の名称はその町の名称を引き継ぐことにする。
そのような町が存在しないならば、新しい市の名称は atcoder とする。
それぞれの町の名称と人口が与えられるので、合併後の新しい市の名称を出力してください。

```
#include<iostream>
#include<string>
using namespace std;
int main() {
	int N;
	string S[1010];
	cin >> N;
	int P[1010];
	int sum = 0;
	for (int i = 0; i < N; ++i) {
		cin >> S[i] >> P[i];
		sum += P[i];
	}
	for (int i = 0; i < N; ++i) {
		if (P[i] > sum/2) {
			cout << S[i] << endl;
			break;
		}
		else {
			cout << "atcoder" << endl;
		}
	}
	return 0;
}
```
間違いのコード。

```
#include<iostream>
#include<string>
using namespace std;
int main() {
	int N;
	string S[1010];
	cin >> N;
	int P[1010];
	int sum = 0;
	for (int i = 0; i < N; ++i) {
		cin >> S[i] >> P[i];
		sum += P[i];
	}
	for (int i = 0; i < N; ++i) {
		if (P[i] > sum/2) {
			cout << S[i] << endl;
			return 0;
		}
	}
	cout << "atcoder" << endl;
	return 0;
}
```
正解のコード。return 0ってこういう意味があるのね今更知った。

C

```
#include <iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
using ll = long long;
const int INF = 1e9;
int main() {
	string S;
	cin >> S;
	int countzero = 0;//０を含む塊の数。
	int countplus = 1;//+の数をカウントし、塊の数を求める
	int checkzero = 0;//すでに塊に０が存在しているか確認する
	for (int i = 0; i < S.size(); ++i) {
		if (S[i] == '0'&& checkzero == 0) {
			countzero++;
			checkzero++;
		}
		else if (S[i] == '+') {
			countplus++;
			checkzero = 0;
		}
	}
    cout << countplus - countzero << endl;
	return 0;
}
```
Railsで不要なファイルを生成しないようにする

#rails g controller ××××××× した時に生成されるStylesheetとか必要ない場合


下記のrails newした後のデフォルトの状態

```config/application.rb
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module ×××××××
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
  end
end

```


編集後のファイル

```config/application.rb
require_relative 'boot'

require 'rails/all'

Bundler.require(*Rails.groups)

module ×××××××
  class Application < Rails::Application
      config.generators do |g|
      g.stylesheets false
      g.javascripts false
      g.helper false
      g.test_framework false
    end
  end
end

```
rails console にエラーが出たが、gem 'rb-readline'で直ったお話 

##環境
- Windows Subsystem for Linux 上の Ubuntu18.04
（Windows10 Home 64bit）
- rbenv 1.1.1-37-g1c772d5
- ruby 2.3.3p222 (2016-11-21 revision 56859)
- rails 5.2.1

##現象
`rails new`で作成したサンプルアプリにて、いつの間にか`rails c` すると以下のようにエラーが出るようになった。

```
$ rails c
/mnt/c/linux_home/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/railties-5.2.1/lib/rails/app_loader.rb:53: warning: Insecure world writable dir /mnt/c/linux_home/.rbenv/versions/2.3.3/bin in PATH, mode 040777
Running via Spring preloader in process 831
/mnt/c/linux_home/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require': libreadline.so.6: cannot open shared object file: No such file or directory - /mnt/c/linux_home/.rbenv/versions/2.3.3/lib/ruby/2.3.0/x86_64-linux/readline.so (LoadError)
        from /mnt/c/linux_home/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi'
        from /mnt/c/linux_home/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register'
        （以下略）
```
##やったこと
三行目の`libreadline.so.6: cannot open shared object file`に目を付け検索したところ、こちらの投稿を発見。

https://github.com/rails/rails/issues/26658

参考にして`Gemfile`に`gem 'rb-readline'`を追加し、`bundle install`したところ、正常に起動するようになった。

```ruby:Gemfile
gem 'rb-readline'
```

解決はしたが、その後に以下のQiitaの記事も拝見した。

https://qiita.com/kure/items/90d6d065e820be528e3f

そういえばWSLのUbuntuを16.04から18.04にバージョンアップしたばかりだった。
同じような現象だろうか？（あまり深入りはしたくない）


##参考にさせていただいたページ
https://github.com/rails/rails/issues/26658
https://qiita.com/kure/items/90d6d065e820be528e3f
ふりかえりの考え方について

スララムで約半年間プロジェクト運営をしてきて、スクラムというフレームワークの中に『ふりかえり』というイベントがあります。それについて私なりの考え方がはじめとは変わってきました。

## ふりかえりがうまくいかなかった頃
- 現在のプロジェクトでは以下のような体制で行っています。
- 5月~5月末
 - 4名 + コーチ1名
     - 全員スクラム未経験

- 6月
 - 4名 + コーチ1名
     - 1名マイナス
     - 1名プラス
         - スクラム経験者

- 7月~
 - 5名 + コーチ(スクラムマスター)1名
     - 1名プラス
     - 1名プラス
         - スクラム未経験者

- 上記を見てもわかるように私も含めてスクラム未経験者が多く、うまくふりかえりができていませんでした。
- ふりかえりがうまくできていないというのはアジェンダが良くないとか改善案が出ていないとかそういうことももちろんあります。
- ですが、そういったことは慣れの問題もあったりKEPTやYWTなどフレームワークで解決することもあります。
- そもそもチームでふりかえりが終わった直後になんか釈然としない、もやもやしているような状態でした。
- 6月が終わったときにコーチから指摘をいただき、なんとなくその原因がわかってきました。

## ふりかえりが少し改善してきた頃
- そのように感じていた頃、私がなんとなくふりかえりをしていてもチームが良くなっていっていくイメージがつかないということを6月末のふりかえりで議題に上げました。
- コーチからは以下のような図でアドバイスをいただきました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/202761/88f76dd5-8d78-a6b4-edd9-6fbea8c6a9ed.png)
- アドバイスとしては主に2つです。
 - 1つ目はチームの方向性を決めること。
     - チームの方向性とは<font color="Red">チームがどうなっていたいか</font>です。
     - たとえば「開発のプロフェッショナル集団になる(開発軸)」とか「生産性のあるチームになる（プロセス軸）」とかです。
     - いわゆるチームとしてのKGIを決定します。
     - チームの方向性が決まっていたらふりかえりで出てくる内容も決定する指針も生まれます。
     - たまに〇〇さんがこうしようと言ったからと後から言う人がいますが、チームの方向性が決まっていたらそもそもチームとしてこうしようと決めたよねという一体感も生まれます（そもそも誰かが言ったとかはどうでもよい話ですが、、、）。
 - 2つ目は進捗を図ること
     - 例えばチームの方向性が 「開発のプロフェッショナル集団になる(開発軸)」とします。
     - その際に開発のプロフェッショナル集団とは<font color="Red">具体的にどうなっていたらその状態であるのか</font>を定義します。
     - いわゆるKPIを決定します。
     - 例えば「開発のプロフェッショナル集団」=「全員がRailsアプリケーションを1からすべて開発できる」とします。
     - ゴールがそこですので、今はそうでないのでしょう。では現地点で考え得るKPIを策定していきます(例えば全員が助けを得ることでRailsアプリケーションを開発できるなど)。
     - 進捗を図ることができるとふりかえりでチームの状況が把握でき、チームが次のステップに進むための次のアクションへも話を波及することができます。
- 上記2点のアドバイスをいただくことでふりかえりの内容もチームのふりかえりへの集中度もあがったと思います。
- ちなみに私のチームでは1つのKGIに対して、主に2つのKPIを策定し、そのKPIを満たすために進捗度をはかったり、プロセス改善をしています(以下のイメージ)。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/202761/215dfb9c-654c-d94c-6483-c7ad90130836.png)

## これから
- 上記でうまくいっているようですが、あくまでチーム内の話です。
- ちなみに今までチームと言っているのは開発チームのことです。
- チーム内での方向性を決める際にPOの意向(=プロジェクトの意向)が全く反映されていません。
- チームはあくまでPOがプロダクトを開発していく上で最適だと考えられて作られています(以下の階層構造のイメージ)。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/202761/2dd5beb3-dc8d-0a9e-585b-21a43f6aaedf.png)
- 私のチームはまだプロセスにしか目に行っていなく、ビジネスとしてこうなりたいからこういった方向性のチームになりたいとかそういった話になっていません。
- コーチからいただいた図を見ていただくと分かりますが、方向性は決めることができますが、間違った方向に行っている場合には逆効果になってしまう可能性もあります。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/202761/4f184934-553d-21d0-634f-04c4458341f1.png)

## 最後に
- ふりかえり、難しいですよね。
- でも正しいふりかえりを正しく実施ことでチームの成功になると信じています。
- 皆さんも良いふりかえりを！
画像から数値を認識する

http://reverent.hateblo.jp/entry/2017/01/10/190322

height 120pix
<img width="125" alt="test_h120.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/212cd230-fb8b-d65d-e9af-5fedd90a3181.png">



height 150pix
<img width="156" alt="test_h150.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/4dfac19f-a4ba-7459-8704-887fd413fc86.png">


80mm
<img width="227" alt="test80.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/0f2fb859-1c8d-5f30-6708-66ec3eb8b94a.png">


100mm
<img width="284" alt="test100.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/fe91b2b0-3e7b-db17-f6e1-a666dc55d60d.png">


<img width="85" alt="test10.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/7ac2c5de-e57e-0f35-48d3-1c579356136d.png">


<img width="227" alt="test09.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/a0cb918d-5f7c-ea58-c3a7-bb2aad0e8d32.png">


<img width="61" alt="test07.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/e55c60a6-be88-4130-b97e-f7565581f280.png">


<img width="687" alt="名称未設定8.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/3e64a782-8628-e78d-a042-a5371140e6d2.png">

<img width="821" alt="名称未設定9.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/43d9ccef-f5cb-1432-4b45-e1bd7ea156dc.png">

<img width="236" alt="test05.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/37477476-fea1-513e-aec0-3c0d74645977.png">

http://danglingfarpointer.hatenablog.com/entry/2015/01/30/220754

https://blog.mudatobunka.org/entry/2016/11/19/134726

http://sakataharumi.hatenablog.jp/entry/2016/09/16/20160916052946/

http://izawa.hatenablog.jp/entry/2012/04/24/142734

http://d.hatena.ne.jp/takuto1981/20121112/1352673152

http://tech.atsu-maru.co.jp/entry/2017/11/04/070000

http://motojapan.hateblo.jp/entry/2018/03/12/094636
PythonにBrain Warsをプレイさせてみた3

# はじめに
Pythonに[Brain Wars](http://translimit.co.jp/services/brainwars/)の Make10 をプレイさせてみた

# Make10 のルール
数字の合計が10になるカードの組み合わせを見つけてタップする

# Demo
![demo.gif](https://qiita-image-store.s3.amazonaws.com/0/185448/5ca64db7-aa38-6e65-864b-2b5de9743dbb.gif)

# 環境
- OS: Ubuntu 18.04.1 LTS
- Python version: 3.6.5
- スマホ: Huawei P10 Lite

[Vysor](https://chrome.google.com/webstore/detail/vysor/gidgenkbbabolejbgbpnhbimgjbffefm)というChromeの拡張プラグインを使って、Ubuntuからスマホを操作している

# コード
```python
import mss
import numpy as np
import time
import cv2
import pyautogui as pag
import itertools
from sklearn.neighbors import KNeighborsClassifier


def grab_screen(bbox):
	"""Capture the specified area on the screen"""
	with mss.mss() as sct:
		left, top, width, height = bbox
		grab_area = {'left': left, 'top': top, 'width': width, 'height': height}
		img = sct.grab(grab_area)
		return np.array(img)[:, :, :3]


def process_img(img):
	"""Extract numbers from each card"""
	img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
	_, img_bin = cv2.threshold(img_gray, 210, 255, cv2.THRESH_BINARY)
	_, cnts, _ = cv2.findContours(img_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
	cnts = list(filter(lambda x: 30 < cv2.boundingRect(x)[-1] < 70, cnts))
	cnts = sorted(cnts, key=lambda x: (cv2.boundingRect(x)[1] // 10, cv2.boundingRect(x)[0]))
	rois = []
	locs = []
	for cnt in cnts:
		x, y, w, h = cv2.boundingRect(cnt)
		locs.append([int(x + w/2), int(y + h/2)])
		cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
		roi = cv2.resize(img_bin[y:y+h, x:x+w], (10, 10)).reshape(1, 100)
		rois.append(roi)
	cv2.imwrite('detection_result.jpg', img)
	locs = np.array(locs)
	rois = np.array(rois).squeeze()
	return rois, locs


def build_knn():
	"""Create and train knn classifier"""
	samples = np.loadtxt('train_samples.data', np.uint8)
	labels = np.loadtxt('train_labels.data', np.float32)
	knn = KNeighborsClassifier(n_neighbors=3)
	knn.fit(samples, labels)
	return knn


def find_combination(nums):
	"""Find a combination which sums to 10"""
	result = [seq for i in range(len(nums), 0, -1) for seq in itertools.combinations(nums, i) if sum(seq) == 10]
	return result


def main():
	grab_bbox = (104, 385, 467, 300)
	knn = build_knn()
	while True:    
		img = grab_screen(grab_bbox)
		rois, locs = process_img(img.copy())
		if len(rois) > 12 or len(rois) < 9:
			print('Done')
			break
		nums = knn.predict(rois).astype(int)  # classify numbers
		while len(locs) > 0:
			idx = (np.abs(locs[:, 1] - locs[-1, 1]) < 5)  # index of cards at the bottom row
			locs_ = locs[idx].tolist()
			nums_ = nums[idx].tolist()
			comb = find_combination(nums_)
			print('Cards to click:', comb[0])
			for num in comb[0]:
				idx_click = nums_.index(num)  # index of card to tap
				x, y = (locs_.pop(idx_click))
				nums_.pop(idx_click)
				pag.click(grab_bbox[0] + x, grab_bbox[1] + grab_bbox[3] - 50)  # tap card
			locs = locs[~idx]  # remove cards at the bottom row
			nums = nums[~idx]  
			if len(locs) > 0:
				time.sleep(0.085)
		time.sleep(0.36)


if __name__ == '__main__':
	main()

```

# 結果
Python便利
obniz（Node.js）で画面に日本語を表示する

![IMG_0755.JPG](https://qiita-image-store.s3.amazonaws.com/0/79577/f75786a4-7262-f0fb-40f2-a3c6f23f0882.jpeg)

[node-canvas](https://github.com/Automattic/node-canvas)を使って日本語を描画します。
obnizで対応しているのは2系以上の最新バージョンなので、`canvas@next`をダウンロードします。

```sh
$ npm i canvas@next
```

`canvas`は1.6系（2018年9月現在）なので、obnizでは使えません！

```javascript
const Obniz = require("obniz");
const { createCanvas } = require('canvas');

var obnizeId = "YOUR-OBNIZ-ID";
var obniz = new Obniz(obnizeId);

obniz.onconnect = async function () {
  obniz.display.clear();
  const canvas = createCanvas(128, 64);
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = "white";
  ctx.font = "15px Avenir";
  ctx.fillText('こんにちは', 0, 20);
  obniz.display.draw(ctx);
}
```

文字を横にスライドさせてみます。

![output4.gif](https://qiita-image-store.s3.amazonaws.com/0/79577/a099bd7a-ead1-8cab-ab03-6a32824ca9c6.gif)


```javascript
const Obniz = require("obniz");
const { createCanvas } = require('canvas');

var obnizeId = "YOUR-OBNIZ-ID";
var obniz = new Obniz(obnizeId);

obniz.onconnect = async function () {

  const canvas = createCanvas(128, 64);
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = "white";
  ctx.font = "20px Avenir";

  for (var i = 0; i < 130; i++) {
    obniz.display.clear();
    ctx.fillText('こんにちは', i, 30);
    obniz.display.draw(ctx);
    ctx.clearRect(0, 0, 128, 64)
    await obniz.wait(100);
  }
}
```

参考：https://obniz.io/doc/sdk/doc/display
IE11以前で動作しないAjax( jQuery )の書きかた

# IE11以前で動作しないAjax( jQuery )の書きかた

IEのブラウザテストをしている際に出会ったバグ。 

誤

```javascript
$.ajax({
    url: 'url',
    type: 'post',
    data: 'data'
})
.done( (data) => {
    console.log(data);
})
.fail( (data) => {
    console.log(data);
});
```
どうやらアロー関数( => )でこけているようだったので、書きかたを変えた。 

正

```javascript
$.ajax({
    url: 'url',
    type: 'post',
    data: 'data'
})
.done(function(data) {
    console.log(data);
})
.fail(function(data) {  
    console.log(data);
});
```

他のブラウザ(chrome、safari)では問題なく動作していたのでIEのみっぽい。 
edgeでも動いたので、IEが存在しない世界線では使えそう。  

※追記
IE11以前がES6に対応してないんですね。
フロントの知識が乏しいと感じました。
[SlackAPI][node-slack-sdk] Workspace内の全てのChannel名を取得する (conversations.list を使う)

### これまでの一般的な方法
普通にググると大抵はこの `channels.list` を使っているサンプルに行き着く。
https://api.slack.com/methods/channels.list

ただし、最近気づいた下記の文言、

> Don't use this method. Use `conversations.list` instead.

他にも移行が必須なケースがあって、例えば `channels.list` は[Shared channels](https://api.slack.com/shared-channels)を返してくれない。ここは場合によっては結構困るので`conversations.list`へ移行した。

https://api.slack.com/methods/conversations.list

## サンプル

`conversations.list` ではpaginationを意識する必要があるが、node-slack-sdkのサンプルを参照すると下記のようになる。
https://github.com/slackapi/node-slack-sdk/blob/master/docs/_pages/web_client.md#pagination

```js
const { WebClient } = require('@slack/client');
const token = process.env.SLACK_BOT_TOKEN;
const web = new WebClient(token);
  
function getChannels() {
  const param = {
    exclude_archived: true,
    types: 'public_channel',
    limit: 200
  };
  let channels = [];
  function pageLoaded(res) {
    // 今回はチャンネル名だけ欲しかったので "name" だけ。
    res.channels.forEach(c => channels.push(c.name));
    if (res.response_metadata && res.response_metadata.next_cursor && res.response_metadata.next_cursor !== '') {
      param.cursor = res.response_metadata.next_cursor;
      return web.conversations.list(param).then(pageLoaded);
    }
    return channels;
  }
  return web.conversations.list(param).then(pageLoaded);
}

getChannels()
  .then((d) => console.log(JSON.stringify(d)))
  .catch(console.error);
```

`conversations.list` に渡すことのできるArgumentsはいくつかあるのでドキュメントを参照のこと。上記の例では、archive済みのチャンネルは省略、Publicチャンネルのみ、1ページ毎に200個まで、と指定している。`limit: 200` の理由は、一応ドキュメントに下記のように記載があるため。

> To begin pagination, specify a limit value under `1000`. We recommend no more than `200` results at a time.

普通にwhileで回してもいいとは思う。
https://blog.frame.ai/migrating-to-the-slack-conversations-api-89692b016eea
Rails Migrationまとめ

RailsのMigrationコマンドを自分用にまとめました。

## モデル作成

```bash
$ rails generate model ＜モデル名単数形＞
```

- example

```bash
$ rails generate model ship
```

## モデル修正

```bash
$ rails g migration Add<列名>To<モデル名> <列名>:<型>
$ rails db:migrate
```

### 列を追加したい例

- User テーブルに locale 列を追加したい例

```bash
$ rails g migration AddLocaleToUser locale:string
$ rails db:migrate
```

### 参照関係を追加したい例

- IssueComment テーブルにRoleモデルの参照関係(role列)を追加したい例

```bash
$ rails g migration AddRoleToIssueComment role:references
$ rails db:migrate
```

### 参照関係を追加したい例(外部キー制約を付けない場合)

```ruby
def change
  add_reference :issue_comments, :role, foreign_key: false
end
```

### 列を削除したい例

- User テーブルの列　locale を 削除したい例

```bash
$ rails g migration RemoveLocaleToUser locale
$ rails db:migrate
```

### 参照関係を削除したい例

- IssueComment テーブルに role 列を削除したい例

```ruby
def change
  remove_reference :issue_comments, :role, index: true, foreign_key: true
end
```

### テーブル名を変更したい例

- User テーブルの名前 users を hoge_users に変更したい例

```ruby
def change
  rename_table :users, :hoge_users
end
```

### 列名を変更したい例

- User テーブルの列 local の列名を locale に変更したい例

```ruby
def change
  rename_column :users, :local, :locale # 列名をlocaleに変更
end
```

### 列の型を変更したい例

- User テーブルの列　locale を text型 → string型 に変更したい例

```ruby
def change
  change_column :users, :locale, :string
end
```

### indexを追加したい例

- Ship テーブルの列　ship_code にindex(Unique制約有)を付けたい場合

```ruby
def change
  add_index :ships, :ship_code, :unique => true
end
```

### indexを追加したい例（複数列）

- ShipEquipment テーブルの列　ship_id,sfi,equipment_model_id にindex(Unique制約有)を付けたい場合

```ruby
def change
  add_index :ship_equipments, [:ship_id, :sfi, :equipment_model_id], :unique => true
end
```

### 既にindexが存在するテーブルにUnique制約を付けたい例

```ruby
def change
  remove_index :ship_equipments, [:ship_id, :sfi, :equipment_model_id]
  add_index :ship_equipments, [:ship_id, :sfi, :equipment_model_id], :unique => true
end
```

### indexが長すぎるため、index名を付けたい例

```ruby
def change
  add_index :satellite_speed_logs, [:ship_equipment_id, :measurement_date], name: :index_satellite_speed_logs_ship_equipment_measurement_date
end
```

## モデル削除

```ruby
def change
  drop_table :users
end
```

## rollback

```bash
$ rails db:version # 現在のバージョンの確認
Current version: 20180816060332
$ rails db:rollback # 1つ前に戻す
$ rails db:rollback STEP=2 # 2つ前に戻す
```

## DBの再構築
```bash
$ rails db:reset
# すべてのテーブルをdrop
# "db/schema.rb" を元にテーブルを再作成
```
西暦→和暦に変換

# 前書き
こんにちは。@mashiです。
今回はPHPにて西暦→和暦の変換を行います。(正直、今更という感じですが…)

正直、かなり粗い作りのため、JavaScript等でバリデーションをかけてあげたらよいかと思います。

# コード
```php
// 入力文字
$input_words = $argv[1]; // 画面から入力の場合は変更してください
$conversion_date = changeConversion($input_words);

echo $conversion_date . "\r\n";

// 西暦を和暦に変換
function changeConversion ($date) {
    // 簡単なエラーチェック
    if (strlen($date) != 8) {
        echo "生年月日を8桁の西暦で入力してください\r\n";
        exit;
    }

    $year = substr($date, 0, 4);
    $month = substr($date, 4, 2);
    $day = substr($date, 6, 2);

    if ($date) {
        switch ($date) {
            case $date > 19890108:
                $year_number = $year - 1988;
                $year_value = "平成";
                break;
            case $date > 19261225:
                $year_number = $year - 1925;
                $year_value = "昭和";
                break;
            case $date > 19120730:
                $year_number = $year - 1911;
                $year_value = "大正";
                break;
            case $date >= 18680908:
                $year_number = $year - 1867;
                $year_value = "明治";
                break;
            default:
                $year_number = $year;
                $year_value = null;
                break;
        }

        //初年度なら元年と返す
        if ($year_number == 1) {
            $year_number = "元";
        }

        $return_value = $year_value . $year_number . "年" . $month . "月" . $day . "日";

        return $return_value;
    }
}
Pythonの辞書機能だけでcsvからユニークデータ抽出してみた。

### データ準備
こんなcsvがあるとする
※フィクション。類似名で実際に存在するキャラクターとは一切関係ない。

```
cat profile.csv

No, 作品, 作品_出典元, 名前, 名前_種類, 年齢
1, 崖の上のxニョ, xブリ, ぽにょ, 魚, 16
2, Frozxn, Disnxy, えるざ,雪女,20
3, リラッxマ, サンxックス, こぐまちゃん,熊,3
4, こげxん, Sanxio, こげぱん,パン,0.1
5, 名x偵コナン, サンデー, こなん,人間,17
6, カピバxさん, Trtworxs, ほわいとさん,カピバラ,3
7, xウルと動く城,xブリ, はうる,魔法使い,100
8, リラッxマ, サxxックス, こぐまちゃん,熊,5
9, アナ雪, Disnxy, えるーざ,雪女,20
```

### やりたいこと
被っているデータを消したデータをcsv出力したい。
No.3とNo.8、No.2とNo.9が被っていそうだが、法則性なく微妙に揺れている。

### 辞書作成 step1

- 作品名と名前の辞書aを作成する

```
a = dict()
with open('profile.csv', 'r') as pfile:
    for line in pfile:
        arr = line[:-1]
        title = arr[1]
        name = arr[3]

        a[title, name] = arr
```

aをこのまま出力するとこんな感じ、

```
No, 作品, 作品_出典元, 名前, 名前_種類, 年齢
1,崖の上のxニョ,xブリ,ぽにょ,魚,16
2,Frozxn,Disnxy,えるざ,雪女,20
8,リラッxマ,サxxックス,こぐまちゃん,熊,5
4,こげxん, Sanxio,こげぱん,パン,0.1
5,名x偵コナン,サンデー,こなん,人間,17
6,カピバxさん,Trtworxs,ほわいとさん,カピバラ,3
7,xウルと動く城,xブリ,はうる,魔法使い,100
9,アナ雪,Disnxy,えるーざ,雪女,20
```
No.3とNo.8の重複は消せたがNo.2とNo.9のはまだ残っている。

### 辞書作成 step2

- 辞書aのキーを変えて出典元、種類、年齢をキーとした辞書を作成する。

```
b = dict()
for arr in a.values():
    presented = arr[2]
    name_category = arr[4]
    age = arr[5] 
    b[presented, name_category, age] = arr
```

これでNo.2とNo.9の重複も消せた。
あとはbをファイル出力するだけ。

```
import csv
with open('result.csv', 'w') as rfile:
    writer = csv.writer(rfile, lineterminator='\n')
    writer.writerows(b.values())
```

結果はこちら

```
No, 作品, 作品_出典元, 名前, 名前_種類, 年齢
1,崖の上のxニョ,xブリ,ぽにょ,魚,16
9,アナ雪,Disnxy,えるーざ,雪女,20
8,リラッxマ,サxxックス,こぐまちゃん,熊,5
4,こげxん, Sanxio,こげぱん,パン,0.1
5,名x偵コナン,サンデー,こなん,人間,17
6,カピバxさん,Trtworxs,ほわいとさん,カピバラ,3
7,xウルと動く城,xブリ,はうる,魔法使い,100
```

でけた。

### まとめ

・辞書機能を用いて揺れてる文字列以外のキーで重複削除ができる。
・データが後勝ちになるのでどっちが残ってもいいケースに限り利用可
海外赴任した感想、困ったこととか。

一年間、米国に赴任してきたので、感想やら困ったこととかを書いておく

この記事を見たエンジニアが海外赴任する際の参考になれば、と思います。

# 前提
- 日本メーカーの若手ITエンジニア
- 初の海外赴任。期間は2017/2 ~ 2018/3
- ニューヨークとロサンゼルスの支社に配属
- 帰国子女でもないし、留学経験もない。海外旅行は１回だけ

# 仕事
日本所属時と比べて考えられないほどの自由度が高い。メーカーだからか、余計にその自由度に魅力を感じた。ハイスペックPCをすぐに買ってくれるし、プロジェクトにおける技術の採用も自由、また庶務系の雑務は全部担当の人任せで良かった。

駐在員はどうしても日本本社との繋がりや現地でのマネジメントの能力も求められる。単なるエンジニアは現地に腐るほどいるので、単なる開発者として赴任するわけではなかった。いわゆる多能工が求められている感じ。

仕事で使う言語は、英語と日本語半々くらい
# 英語勉強
もちろん最初は、全然話せなかった。
どうせ英語勉強するなら技術能力も上げたいなーって思って下記を実践してた

## 技術系の英語勉強
- [PluralSight](https://www.pluralsight.com/)で英語の技術勉強
    - 海外で有名らしいテクノロジー教育のサイト
    - わりと綺麗な発音で、そこそこ新しい技術のオンラインセミナーが多く重宝
    - 英語のリスニング勉強ついでに技術の勉強にもなるのでかなりお勧め
    - 自分は仕事と関係ないAndroidやJSのセミナーを聞いてた
- イベントのセッションをYoutubeでストリーミング
    - Google I/O とかのセッションを仕事中ずっと聞いてた
    - イベント系の英語は、割とゆっくりはっきり話してくれるので聞きやすい
- 情報収集もなるべく英語で
    - [TechCrunch](https://techcrunch.com/)とかギーク系サイトもなるたけ英語で
    - SDKとかも全部英語版を使うように。結局仕様書とか英語で書かないといけないので勉強になった。
- Meetupへの参加
    - 結局できなかったけど、Meetup系でテクノロジー系のイベント参加もしたかった

# 困りごと

- ハードカバーの日本語技術書は手に入りにくい
    - 紀伊国屋書店とかいけばかなり割高だけど入手可能
    - 電子版は当然手に入る
    - 日本から来る赴任者や出張者に買ってきてもらったりもした
- PCの購入に少し躊躇する
    - USキーボード配列だったり、懸念がいくつかあり購入できず

技術系で困ったことは案外少ない。

# 感想
多くのエンジニアは会社以外にも何かしらスタートアップに入っていたり、プロダクトを趣味で作っている人が多く、総じて刺激的な環境だった。