OmniAICreator/Qiita-1.07M huggingface dataset:
mongoDBのインストール

## 公式から
mongoDBはJSONのようなkey,valueのwebDB用のシンプルなデータベース。
基本javascriptのクエリから操作するので最近の非同期のwebサービスなんかでよく使われる。
いわゆるSQLコマンドが使えない、noSQLってやつです。

[mongoDB公式](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/)
公式サイトにあるようにubuntuが提供しているmongodbパッケージはオフィシャルではなく、mogodb-orgが公式のパッケージとなる。

# インストール
個人的なもも書きなので、公式サイトを見て。

```
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
```
```
$ echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list
```
```
$ sudo apt-get update
```
```
$ sudo apt-get install -y mongodb-org
```
### デーモン起動設定
```
$ sudo systemctl enable mongod 
```
### 確認
```
$ sudo systemctl status mongod
● mongod.service - MongoDB Database Server
   Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: https://docs.mongodb.org/manual

```

# アンインストール
再インストール時は、パーケージが紛らわしいが故、競合トラブルが発生しがちなので下記で完全削除。

```
$ sudo apt-get purge mongodb mongodb-server mongodb-server-core mongodb-clients
$ sudo apt-get purge mongodb-org mongodb-org-server
$ sudo apt-get autoremove
```

### コマンド
collectionsがからになるとDBも消える。
操作は対象のDBに入って行う。

```
$ mongo
DB一覧
> show dbs
DBに入る
> use hodedb
DB構造
> db.stats()
collection一覧
> show collections
collection削除
> db.mycollection.drop()
DB削除
> db.dropDatabase()
```
Rで単回帰から重回帰-#1【単回帰】

コーセラのMLを見て回帰(regression)が出てきたので単回帰についてまとめる。
ついでに興味あった重回帰も書きなぐっていく。

#単回帰

回帰は連続値の関係性を使って、予測値を計算する方法。
単回帰では目的変数 y を予測するために、説明変数 x があり、
予測式は y = f(x)　となる。
いくつかの(x, y)のデータ(教師データ)を使ってモデル式を作って
新しい予測したいデータ(x,?)の?を埋めることが目的。

baseのデータセット「cars」を使った。

```R
plot(cars)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/03b96506-1800-eed0-041c-c7baaf3200be.png)

1920年代の車の速度とブレーキをかけてから停止までの距離

一番右上を見てみると、速度25 で走っている車は停止まで120までは動き続ける。
(単位はマイル/時とメートル?)
plotだけでも相関がありそうで。xとyの関係をモデルにしようとしたら右肩上がりの直線が書けそう。
まずこの時点で二次関数っぽかったら線形の単回帰は避けるべきなんでしょうね。

とりあえず線形単回帰。

```R
model=lm(cars$dist~cars$speed)
model
```

```
Call:
lm(formula = cars$dist ~ cars$speed)

Coefficients:
(Intercept)   cars$speed  
    -17.579        3.932  
```

速度から停止距離を割り出せるように回帰式を作りmodelに格納した。
model内にはモデル関数が出来ていて
y = 3.932×speed + (-17.579)
切片-17、傾き3.9の直線式が得られた。
どのくらいデータを説明できていそうなのかplotしてみる。


```R
bind=NULL
for (x in 0:25){
val=3.932*x-17.579
bind=c(bind,val)
}

points(bind,col="red",type="l")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/1b6c9233-c3c1-1034-6988-98a85e07451d.png)

モデルとしてよさそうだけれども傾きがもう少し小さくても良さそう。
右上の外れ値が影響してしまっているのでしょう。
モデルがデータをどれだけ説明しているのか見てみます。

```R
summary(model)
```

```
Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -17.5791     6.7584  -2.601   0.0123 *  
cars$speed    3.9324     0.4155   9.464 1.49e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 15.38 on 48 degrees of freedom
Multiple R-squared:  0.6511,    Adjusted R-squared:  0.6438 
F-statistic: 89.57 on 1 and 48 DF,  p-value: 1.49e-12
```
決定係数(R-squared)を見ると0.65となっていて
モデル関数で予測した値と、実際の値は65%くらいが一致していそうということでしょうか。
plotしてホントなのか確かめます。

```R
plot(cars$dist,model$fitted.values)
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/4540d235-7d3c-0f40-857b-d80f56b27523.png)

65%ですか。
この図でいう右上の外れていそうな値を抜いてみたらどうなるのでしょうか

#外れていそうな値を抜く

```R
new_data=cars[cars$dist<100,]
#29行目の120が抜けた
plot(new_data)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/5f7a2e03-3964-a25a-6749-9c461f22c83e.png)

大分きれいな関係になっていそうです。
またモデルを作って決定係数を調べてみます。

```R
new_model=lm(new_data$dist~new_data$speed)
summary(new_model)
```

```
Call:
lm(formula = new_data$dist ~ new_data$speed)

Residuals:
    Min      1Q  Median      3Q     Max 
-26.789  -9.149  -1.672   8.013  43.048 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)    -14.0021     6.2951  -2.224    0.031 *  
new_data$speed   3.6396     0.3918   9.290 3.26e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 14.1 on 47 degrees of freedom
Multiple R-squared:  0.6474,    Adjusted R-squared:  0.6399 
F-statistic: 86.31 on 1 and 47 DF,  p-value: 3.262e-12
```

一個外れ値を外したくらいでは変わりませんでした。
傾きがもう少し小さいほうがデータを説明できるモデルになるのでは?
と考えていましたが、
この時代の車は停止するまでの距離が伸びてしまう傾向にあるということをモデルが説明してくれていると考えると納得です。
現在の車のようにロバストな出来ではなかったんですかね。

外れ値と思ったものを抜いて、抜く前と比較して、
その際どちらのモデルを採択するのかしっかり議論するというのは実験した人や実情を知っている人としっかり会話しないといけないのかもしれません。


[次の記事]()は重回帰についてです。
仙台CTF2018 Net.3 Tomcat脆弱性 100

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/0749e629-0b57-91d5-3946-e2a0d2526a6a.png)

#解いてみた

さっきの問題のpcapファイルを確認します。
さっきの問題で攻撃元のIPアドレスは判明しているので、sourceを絞ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/452d1b5a-0f0c-f013-d3da-b761bc3ab363.png)

最初の方にPUTしているレアなパケットを発見しました。
tomcatの脆弱性で外部からPUTしてファイルを置くことができるものなんでしょうか。
Google検索で「tomcat put」で検索してみます。

[Tomcatに見つかった3つの脆弱性について - WAF Tech Blog ｜ クラウド型 ...](https://www.scutum.jp/information/waf_tech_blog/2017/10/waf-blog-050.html)

先頭に出てきたサイトを見ると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/70780ecc-99d4-5bd8-9192-64daf972c788.png)


と書かれていました。
なーんだ、3つなら・・・ということでそれぞれ答えに入力してみると一つが答えでした。
Nuxt.jsで本番環境のみconsole.logを削除する

開発用に`console.log`で色々出しておきたいけど、本番では出したくない😑ってときに。

## 経緯
元は**UglifyJsPlugin**で`drop_console`を指定していたのだけれど、ある時から

```
Unexpected token: keyword «const» [./node_modules/vuejs-datepicker/dist/vuejs-datepicker.esm.js:600,0]
```

と怒られるようになってしまった。
UglifyJsがどうやらES6+に非対応らしく、利用しているプラグインのアップデートで怒られるようになったのではと。
`exclude`指定とか試したんだけどどうもうまくいかないので、UglifyJsを諦めた＼(^o^)／

## terserのオプション指定でconsole.logを消す
Nuxt 2.1.0 以降で、**terser**のオプションを指定できるようになってます！

```js:nuxt.config.js
  build: {
    terser: {
      terserOptions: {
        compress: { drop_console: true }
      },
    },
  },
```

こんな感じで無事console.log削除。

**terser**も**UglifyJS**もWebpackで使うミニマイザ（圧縮ツール）ですが、
Nuxtデフォルトのミニマイザはterserです。
この辺りをよく理解せずに、古い記事を参考にしてUglifyJS使っちゃってたのですが、
オプション触れるのであればterserを使った方が良いですね🙌


## 参考
https://ja.nuxtjs.org/api/configuration-build/#terser
https://github.com/webpack-contrib/terser-webpack-plugin
ffi-1.11.1がMac OSX High Sierraでのインストールでコケる件

解決するのがめんどくさかったのでメモしておく

brewでlibffiを予めインストール

```sh
$ brew install libffi
```
linkを試みるとこんなメッセージがでてくるので `PKG_CONFIG_PATH` のほうをコピっておく

```sh
$ brew link --force libffi
Warning: Refusing to link macOS-provided software: libffi
For compilers to find libffi you may need to set:
  export LDFLAGS="-L/usr/local/opt/libffi/lib"

For pkg-config to find libffi you may need to set:
  export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
```
ffiのgemをインストールする際に `PKG_CONFIG_PATH` を指定

```sh
$ PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig" gem install ffi
Building native extensions. This could take a while...
Successfully installed ffi-1.11.1
Parsing documentation for ffi-1.11.1
```
見事インストールされた

参考: https://hawksnowlog.blogspot.com/2019/05/homebrew-ruby-ffi-pkgconfig.html
仙台CTF2018 Net.2 攻撃元の特定 100

#問題

http://ctf.sectanlab.jp/2018/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/9cb0639a-7515-aca6-11b4-8a1d96616ee9.png)


#解いてみた

問題ファイルを開くとpcapファイルが入っていました。
wiresharkで開いてみます。

グローバルIPからプライベートIPに通信がたくさんあるものが攻撃元と予想できるので、調べてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/988ced4b-b7fd-fdce-676b-75fc0b144443.png)

予想通り一番数が多いのが答えでした。
JavaScript で関数単位で細かく実行確認をしながら開発するには

## はじめに

会社の先輩からいただいたアドバイスがとても参考になったので、簡単に記事にまとめたいと思います。

## 状況

JavaScript のテストフレームワークをまだ導入できていないアプリを開発していました。

RSpec の model spec のように、関数単位で動作を確認するということはしておらず、画面確認で複数の関数が動作していることを確認していく、という方法をとっていました。

テストフレームワークを導入をするという選択肢もあるとは思うのですが、当時は機能開発を優先する状況だったので、導入していない状況でどうスムーズに開発していくかを考えていくというところでした。

## tl;dr

そんな中会社の先輩とペアプロしたときに、いただいたアドバイスは以下でした。

* 試したい処理を関数に切り出す
* その関数に `window.` をつけてグローバルから参照できるようにする
* デベロッパーコンソールからその関数を実行しつつ修正していく
* 開発が終わったら`window.` を外す

## 進め方

### 試したい処理を関数に切り出す

まず、開発中の機能を関数に切り出します。

```javascript
const sampleFunction = () => {
  return 'sample function'
}
```

### 関数に `window.` をつけてグローバルから参照できるように

次に、開発している関数をグローバルから参照できるようにします。これにより、ブラウザ上で関数を参照できるようになります。

```javascript
window.sampleFunction = () => {
  return 'sample function'
}
```

### デベロッパーコンソールからその関数を実行しつつ修正していく

その後、ブラウザのデベロッパーコンソール上で該当の関数を実行して確認します。ここで想定と違う動作をしている場合などは、`debugger` をつけてデバッグすることもできると思います。

![4e818391.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222030/da1437fb-588e-38b3-3802-11103261b77a.png)



### 開発が終わったら`window.` を外す

`window.` がついている状態ですと、いつでも該当の関数を実行できる状態になってしまいます。

開発が終わったら、忘れずにその関数をグローバルに定義した状態から元の状態に戻しましょう。

```javascript
const sampleFunction = () => {
  return 'sample function'
}
```

## おわりに

方法としてはとても簡単なのですが、自分としてはとても JavaScript の開発がしやすくなりました。

テストフレームワークを使うのが本来あるべきではあると思いますが、今回それが無くても、開発単位を小さくして、開発・確認のサイクルを高速に回す考え方は適用できる、ということを改めて実感しました。

今後 JavaScript の開発でなくても同じ状況に直面したときは、開発・確認を細かくしていく方法を調べて実践できればと思いました。

アドバイスをくださった  @mat_aki さんありがとうございました！
SourceTree (ソースツリー) GUI(グラフィカルユーザインターフェース)

##SourceTree(ソースツリー)の使い方
※SouceTreeをダウンロードしている前提で進めていきます｡
SouceTreeは無料で利用できます｡
SourceTreeからBitbucketの会員登録など､手順を進めていきます｡
↓    ↓   ↓ URL↓↓↓
https://www.atlassian.com/ja/software/sourcetree

####全体の流れ
fork→clone→作業→add,commit,push→プルリク→リモート追加→プル→作業→add,commit,push→プルリク→プル→作業→繰り返し

####フォーク
フォークしたいリポジトリ(自分は権限なし)をGithubの画面で開き､Forkする｡
####クローン
SourceTreeの画面で､ローカルのボタンを押したまま&新規ボタンを押す
→"URLからクローン"をする
フォークした自分のリポジトリURLを貼り付け､保存場所を指定し､クローン完了

####その後の流れ
`checkout` `add` `commit` `push`→プルリク
リモートを追加して `pull`
はカーソルで操作できます｡
プルリクはコマンド利用の時と同様に､Githubのブラウザ画面から操作します｡

####変更箇所
ファイルを変更すると､速攻でSourceTreeにどこが変更されたか､変更履歴が出ます｡
↓
変更したファイルを選択して､`add` `commit` `push`ができます｡

####プルする
現在は`origin`からしかプルできない状況｡
`リモートを追加`して､プル元のリモートリポジトリを設定｡
プル元のリモートリポジトリを選び､プルする｡

(追加するリモートのURLはGithubから分かります｡)


####gitコマンドとの違い
※コマンドでの`add`は､SourceTreeだと`ステージング`です｡
※コマンドでの`remote add`は､SourceTreeだと`リモートの追加`
オフラインどう書く第14回の解答

問題はこちら->http://nabetani.sakura.ne.jp/hena/ord14linedung/

　だいぶ前に書いていたのを一部修正
　入力をmanda/3で武器のリストとモンスターのリストに分け、
　battle/3でmon/1とパターンマッチさせて、
　持っている武器で倒せるモンスターがあれば、モンスターのリストから該当のモンスターを除き、
　そのモンスターを倒して得られる武器を持っている武器に加えることをくりかえし、
　倒せるモンスターがないか、すべて倒したら終了。

```Prolog
%SWI-Prolog (version 7.4.2)
%start
%:-initialization(start).  %ideone
mon(['B',a,c]).
mon(['D',c,e]).
mon(['F',e,g]).
mon(['H',g,i]).
mon(['J',i,k]).
mon(['L',k,a]).

solve(Input,N):-
    manda(Input,Arms,Monster),length(Monster,N0),
　  battle(Monster,Arms,Result),length(Result,N1),N is N0-N1,!.

manda(Input,Arms,Monster):-
 　 atom_chars(Input,Output),
    findall(X,(member(X,Output),char_type(X,lower)),Arms),
    subtract(Output,Arms,Monster).
    
battle([],_,[]).
battle(Monster,Arms,Result):-
 　(member(Arm1,Arms),mon([M,Arm1,Arm2]),select(M,Monster,Monster1)
  　->(Arms1=[Arm2|Arms],battle(Monster1,Arms1,Result));Result=Monster).

start:-str(S),split_string(S,"\s,\n","\s",L),pre(L),!.

pre([]):-!.
pre([_,B,C|T]):-solve(B,R),number_chars(CN,C),
      (R=:=CN->Str=" pass";Str=" fail"),write(Str),write(" "),writeln(R),pre(T).


str("0  gLDLBgBgHDaD    6
1       DBcDLaLgDBH     6
2       JJca    0
3       FJDLBH  0
4       HJBLFDg         6
5       HBaDLFJ         6
6       DJaHLB  2
7       gDLHJF  3
8       cJFgLHD         5
9       FFBJaJJ         1
10      FJeJFBJ         2
11      iJFFJJB         3
12      JBJiLFJF        5
13      JDiFLFBJJ       8
14      BDFDFFDFFLLFFJFDBFDFFFFDDFaDBFFB        28
15      DDFBFcBDFFFFFFLBFDFFBFLFDFDJDFDF        24
16      FDLBFDDBFFFeFFFFFDFBLDDFDDFBFFJF        16
17      FDBFFLFDFFDBBDFFBJDLFgDFFFDFFDFF        0
18      FDiFLDFFFFBDDJDDBFBFDFFFBFFDFLFF        31
19      FDFDJBLBLBFFDDFFFDFFFFFDDFBkFDFF        30
20      HBkFFFFHBLH     3
21      FBHHFFFHLaB     2
22      LFHFBBcHFHF     0
23      LFBHFFeFHBH     7
24      LgFHHHBFBFF     3
25      FFiFHBHLBFH     0
26      BFHHFFHBeFLk    10
27      FHFaBBHFHLFg    5
28      FFgacaFg        0
29      JHDaDcBJiiHccBHDBDH     9
30      FHJJLckFckFJHDFF        12
31      DeDHJHDFHJBLHDLLDHJLBDD         22
32      gJLLLJgJgJLJL   0
33      DaaaDDD         0
34      HFeJFHiBiiBJeJBBFFB     9
35      FJFFJDBHBHaLJBHJHDLHkLLLFFFgJgHJLHkJkB  32
36      giFLBiBJLLJgHBFJigJJJBLHFLDLL   23
37      cgkLJcLJJJJgJc  2
38      LDFHJHcFBDBLJBLFLcFJcDFBL       22
39      JJHHHkHJkHLJk   1
40      kHHBBaBgHagHgaHBBB      11
41      HDBFFDHHHDFLDcHHLFDcJD  20
42      HFFFHeFFee      7
43      gLLDHgDLgFL     1
44      JJJBBaBBHBBHaLBHJ       7
45      FBFBgJBDBDgF    0
46      LLLLakakLakLL   7
47      HeJHeJe         0
48      LDFLBLLeBLDBBFFBLFBB    4").
```
[PHP]explode()の「区切り文字列」配列版

# やりたいこと
`explode('_', '111_222');`
とするだけで、`111`と`222`に分割してくれる便利なexplodeさん。
上記の`'_'`の部分を、配列で渡したい、みたいな欲求が生まれた。

具体的には、
`explode_ex(['_', '-'], '111_222-333');`
とした場合に、戻り値が`array(3) {[0]=>'111',[1]=>'222',[2]=>'333'}`となってほしい。

※なぜこんなことを思い立ったのかが思い出せない。

# 作った関数
引数は基本的に、本家explodeさんに準拠。delimiterだけ配列OKにする。

```
/**
 * explodeのdelimiterが配列でも大丈夫版
 *
 * @param array|string $delimiter 区切り文字列
 * @param string       $string    入力文字列
 * @param int          $limit
 * @return array
 */
function explode_ex($delimiter, $string, $limit = PHP_INT_MAX) {
	if (is_string($delimiter)) {
		// 文字列型を渡されたら、普通にexplode
		return explode($delimiter, $string, $limit);
	} else if (!is_array($delimiter)) {
		// stringでもarrayでも無ければ、処理せずに返却
		return [$string];
	}

	$delete = 0;
	if (intval($limit) === 0) {
		// limitに0が入れられていた場合、1にしておく(explode準拠)
		$limit = 1;
	} else if (intval($limit) < 0) {
		// マイナスの時は、最後の -limit 個の要素を除く全ての構成要素が返されます
		$delete = -1 * $limit;
		$limit = PHP_INT_MAX;
	}

	$list = []; // 分割した後の内容はここへ

	// 上限数まで分割
	for ($count = 0;$count < $limit;$count++) {
		// 複数あるdelimiterのうち、最初に出てくる文字を探す
		$min = strlen($string);
		$target = '';
		foreach ($delimiter as $search) {
			$position = strpos($string, $search);
			if ($position !== false && $min > $position) {
				$min = $position;
				$target = $search;
			}
		}

		// 見つからない or 次で上限数に達してしまう場合
		if ($target === '' || ($count + 1) === $limit) {
			// 返却用配列にそのまま入れる
			$list[] = $string;

			// ループ終了
			break;
		}

		// 最初に出てくる文字で2分割し、前半を返却配列へ、後半は更に分割
		list($list[], $string) = explode($target, $string, 2);
	}

	// 末尾削除
	if ($delete > 0) {
		for ($i = 0;$i < $delete;$i++) {
			array_pop($list);
		}
	}

	return $list;
}
```

# 動作結果

```
var_dump(explode_ex(['/', '-', ':', ' '], '2019/07-20 00:20:30'));
// result ->array(6) { [0]=> string(4) "2019" [1]=> string(2) "07" [2]=> string(2) "20" [3]=> string(2) "00" [4]=> string(2) "20" [5]=> string(2) "30" }

var_dump(explode_ex(['/', '-', ':', ' '], '2019/07-20 00:20:30', 3));
// result ->array(3) { [0]=> string(4) "2019" [1]=> string(2) "07" [2]=> string(11) "20 00:20:30" }

var_dump(explode_ex(['/', '-', ':', ' '], '2019/07-20 00:20:30', -2));
// result ->array(4) { [0]=> string(4) "2019" [1]=> string(2) "07" [2]=> string(2) "20" [3]=> string(2) "00" }

var_dump(explode_ex(['あ','い','う'], 'qazかＸSＷあeｄcきVＦRいtｇbきNＨYうuｊmくLＫI'));
// result ->array(4) { [0]=> string(13) "qazかＸSＷ" [1]=> string(13) "eｄcきVＦR" [2]=> string(13) "tｇbきNＨY" [3]=> string(13) "uｊmくLＫI" }
```
C#　-イベント-

C#学習中のため、学習内容をメモしていく。
間違いやアドバイスがあればコメントからよろしくお願いします。

#イベント
イベントの発生を機にあらかじめ決められたコードを実行する

```
［修飾子］ event デリゲート型 イベント名
```

サンプルコード

```C#
class EventBasic
{
    static void Main(string[] args)
    {
        // イベントハンドラーを追加
        var ev = new MyEvent();
        ev.KeyCommand += OnKeyCommand; // ------③
        OnKeyCommand("");

        // イベントが発生する処理を実行
        ev.Run();
    }

    static void OnKeyCommand(string data)
    {
        switch (data.ToLower())
        {
            case "c":
                Console.WriteLine("おはよう");
                break;
            case "x":
                Console.WriteLine("こんばんは);
                break;
            default:
                Console.WriteLine("認識できないコマンドです");
                break;
        }
    }
}

// デリゲートを準備
delegate void KeyCommandEventHandler(string data); // ------①

class MyEvent
{
    // イベントを準備
    public event KeyCommandEventHandler KeyCommand = ValueTuple => { }; // ------②

    public void Run()
    {
        Console.WriteLine("コマンドを入力して下さい");
        while (true)
        {
            Console.Write("コマンド：");
            var input = Console.ReadLine();
            // イベントを発生
            KeyCommand(input);
        }
    }
}
```

① イベントハンドラーのための型をデリゲートとして準備
② MyEventクラスのイベントとして登録
③ イベントハンドラー(呼び出される処理)を登録
KeyCommandイベントが発生すると、登録されたOnKeyCommandメソッドが実行される

#参考した本
独習C#

おわり。
２つの時間の重なりを計算する

#はじめに

時間と時間の重なりを計算するロジックを考えていて（業務アプリケーションで）
関数が用意されているのではと思い、ネットで色々探してみたものの、
適当なものが見つからず、自作しました。
考えてみるとロジックは簡単だったので、公開します。
# 具体的に
例えば、
業務時間が09:00〜14:10だとして、
休み時間が、10:00〜10:20 12:00〜12:30 14:00〜14:20とあった場合

業務時間中に休み時間をとったのは、
10:00〜10:20の20分間
12:00〜12:30の30分間
14:00〜14:10の10分間
であって、合計60分間ですね。

机上で計算すると単純なのですが、いざ、プログラムを組むとなると
少し面倒な気がします。

#技術解説

```
def time_diff(m1, m2, n1, n2):
  if not(n2 < m1 or m2 < n1 ):
     td = (n2 if n2<m2 else m2) - (n1 if m1<n1 else m1)
     return round(td.seconds / 60)
  return 0
```
m1とm2は、業務時間　09:00、14:10
n1とn2は、休み時間　10:00、10:20のdatetime型をそれぞれセットします。

```
  if not(n2 < m1 or m2 < n1 ):
```
まず、if notで、休憩時間が、業務時間が超えていないかをチェックします。

```
     td = (n2 if n2<m2 else m2) - (n1 if m1<n1 else m1)
     return round(td.seconds / 60)
```
そのあと、終了時間から開始時間を引き算して、経過時間（秒）を分に変換しています。
終了時間は、業務時間（終了）と休憩時間（終了）を比較して、より小さい方を、取得しています。
開始時間は、終了時間とは逆に、業務時間（開始）と休憩時間（開始）を比較して、より大きい方を、取得しています。
それにより、業務時間と休憩時間の重なりの開始時間と終了時間を判定しています。

#サンプルソース

```python:Main.py
import datetime

def time_diff(m1, m2, n1, n2):
  if not(n2 < m1 or m2 < n1 ):
     td = (n2 if n2<m2 else m2) - (n1 if m1<n1 else m1)
     return round(td.seconds / 60)
  return 0

dt1 = datetime.datetime.strptime('09:00', '%H:%M')
dt2 = datetime.datetime.strptime('14:10', '%H:%M')

rest1 = datetime.datetime.strptime('10:00', '%H:%M')
rest2 = datetime.datetime.strptime('10:20', '%H:%M')
rest = time_diff(dt1, dt2, rest1, rest2)

rest1 = datetime.datetime.strptime('12:00', '%H:%M')
rest2 = datetime.datetime.strptime('12:30', '%H:%M')
rest += time_diff(dt1, dt2, rest1, rest2)

rest1 = datetime.datetime.strptime('14:00', '%H:%M')
rest2 = datetime.datetime.strptime('14:20', '%H:%M')
rest += time_diff(dt1, dt2, rest1, rest2)

print(rest)
# 60

```
# まとめ
上の技術解説では、00:00〜24:00で計算していますが、日を超える場合が、想定されるのであれば、
時刻だけでなく、年月日も含めれば、成り立つロジックになっていると思います。
macOS +homebrew でopensslをソースからビルドしたPythonで使う


|  | |
|---|---|
|version  |2019, July  |
|macOS| 10.14, 10.15|
|Python  |3.7.4  |

超ハマったので共有がてら書いておきます。
macOS 10.14 MojaveでPython をソースから入れて `pip install`するとopensslにリンクできてないというエラーがでてしまいました。
よくよく調べると`import ssl` したときにこんなエラーがでるようになってしまった。

```python
>>> import ssl
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/python-3.7.4/ssl.py", line 60, in <module>
   import _ssl             # if we can't import it, let the error propagate
ImportError: No module named _ssl
```


## ビルドする手順

ここではhomebrewでopenssl入れてますが、他のinstall方式でも同じだと思います。
configure するときに `--with-openssl` でディレクトリを指定することが必要でした。

```bash
$ brew install openssl
# /usr/local/opt/openssl　にインストールされる
```

```bash
$ curl https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz
$ tar xzvpf Python-3.7.4.tgz
$ cd Python-3.7.4
$ ./configure --with-openssl=/usr/local/opt/openssl
$ make
$ make install
```

こんなんを実行してsslのバージョンが表示されれば成功

```python
$ python -c "import ssl; print(ssl.OPENSSL_VERSION)"
OpenSSL 1.0.2s
```

## 参考

- https://stackoverflow.com/questions/46457404/how-can-i-compile-python-3-6-2-on-macos-with-openssl-from-homebrew
    - Guidoがstackoverflow.comに書いてくれてました。
- http://pelican.aodag.jp/20140503-python-multiple-version.html

先人たちに感謝
SVG ファイル とは (.svg)

# 目的
拡張子「.svg」についてまとめる。

# SVGファイルの概略
- 画像ファイルの拡張子の一種
- PNG, JPEG, GIFとは描画方法が異なる。
- PNGなどは「ラスタ形式」、SVGは「ベクタ形式」
- CSSやJavaScriptで動きをつけることができる。
- 画像なのにテキストで記述されている。→テキストエディタで編集が可能。

# ベクタ形式
- 画像データの頂点の位置と、頂点をつないだ線、色、曲線などを数値化して再現したもの。
- 代表的なファイルはやSVGやPDFがベクタ形式。
- 画像データが数値として保存されているため、リサイズされても数値をリサイズされた比率に合わせることにより画像が劣化することがない。
- 複雑すぎると表現することが難しい場合がある。

# まとめ
- 画像劣化がないのでSVGファイルはWebサイトのレスポンシブデザインに向いている。
- アイコンなどは積極的にSVGファイルを使用する。
before_actionで共通の変数を定義する

ApplicatinControllerでは、共通して使いたい変数を、一括で処理する事ができる


画像では、before_actionを用いてset_current_userメソッドを定義している。
@current_userという変数に代入されている。
<img width="555" alt="スクリーンショット 2019-07-20 10.09.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439275/86cba886-6e5c-fd8b-c859-b98bc6cf8c84.png">


実際にビューで使用されているのが、こちら
<img width="639" alt="スクリーンショット 2019-07-20 10.17.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439275/397426c4-4309-a1b9-7eda-9da26ffc5d89.png">
Unity上でAngleSharpを利用したスクレイピングを行う

##自己紹介
こんにちはゆずです。@Yuzu_Unity
自分はUnityエンジニア・3DCGデザイナーの学生です。（軸はエンジニア　4年ほど…）
#はじめに
Unity上でapiを利用せずスクレイピングで色々取れないかなぁと思って
調べて動かせたのでとりあえずメモ(スクレイピングをよくわからない…)
※AngleSharpはv0.10以降かなりAPIが変わっているみたいなので他の記事はあまり参考にならないみたいです…
今回利用したのはv0.12.1です。

#今回利用するもの
VisualStudio2017 

Unity2018.3以上(UniTaskを利用するため)

UniTask
https://github.com/Cysharp/UniTask

AngleSharp
https://github.com/AngleSharp/AngleSharp

AngelSharp.Js
https://github.com/AngleSharp/AngleSharp.Js

Jint
https://github.com/sebastienros/jint


#AngleSharpとは？
とりあえずC#でマルチプラットフォームにスクレイピングが行えるライブラリ
Unity対応しているらしい…
![キャプチャ.PNG](https://raw.githubusercontent.com/AngleSharp/AngleSharp/master/header.png)

#環境構築
##1.dllを手に入れる
方法は2通り
プロジェクトデータをダウンロードしビルドを行うか
パッケージマネージャーから取得するかです。
後者のほうが簡単です。
今回は
AngleSharp.dll
AngelSharp.Js.dll　(Jsを有効にするため)
Jint.dll (AngelSharp.Jsを使う際必須)
をインポートしました。

Assets/Plugins内に配置します
(その他UniTaskをインポート＆設定)

##使い方

パース方法2種類あるそうです
名前空間が過去バージョンよりかなり変わっています。

```c#
    using UniRx.Async;
    using AngleSharp.Html.Parser;
    using AngleSharp.Html.Dom;
    using System.Net.Http;

    async UniTask<IHtmlDocument> Parce()
    {
        var parser = new HtmlParser();
        using (var client = new HttpClient())
        using (var stream = await client.GetStreamAsync(new Uri(uri)))
        {
            return await parser.ParseDocumentAsync(stream);
        }
    }
```
```c#
   using UniRx.Async;
   using AngleSharp;
   using AngleSharp.Dom;

   async UniTask<IDocument> Parce()
    {
        // WithJs()で、JavaScriptを有効 動作してるか不明
        var config = Configuration.Default.WithDefaultLoader().WithJs();
        var context = BrowsingContext.New(config);
        return await context.OpenAsync(uri);
    }
```

その他使いかた等は…
https://qiita.com/NekozeDaisensei/items/c74f71e5d79d6de05841

##とりあえずGitHubにテストデータ上げてみました...
https://github.com/yuzu-unity/UnityAngleSharpScraping

ツイッターURLをスクレイピング
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/fdd0f813-6a5f-89ea-ca8e-2b750d9101d9.png)


#余談
使い道が特にないが…
Unity上でも動くということが確認できたのでよしとする…
自分はスクレイピングについて知らないため、いろいろテストしてほしい…
homebrewでインストールしたパッケージのアップデート

homebrew経由でnodebrewをインストールしていて、久しぶりにnodeのバージョンを変更しようとした時にエラーになったための備忘録(すぐ忘れる)


最新の安定板を入れる時にエラーになる

```
$ nodebrew install-binary stable 
v12.6.0 is not found

Can not fetch: https://nodejs.org/dist/v12.6.0/node-v12.6.0-darwin-x64.tar.gz
```

単純にnodebrewのアップデートを行えば問題ないが、homebrew経由でインストールしている場合は

```
$ brew upgrade nodebrew
==> Upgrading 1 outdated package:
nodebrew 0.9.6 -> 1.0.1
==> Upgrading nodebrew 
==> Downloading https://github.com/hokaccha/nodebrew/archive/v1.0.1.tar.gz
==> Downloading from https://codeload.github.com/hokaccha/nodebrew/tar.gz/v1.0.1
######################################################################## 100.0%
==> Caveats
You need to manually run setup_dirs to create directories required by nodebrew:
  /usr/local/opt/nodebrew/bin/nodebrew setup_dirs

Add path:
  export PATH=$HOME/.nodebrew/current/bin:$PATH

To use Homebrew's directories rather than ~/.nodebrew add to your profile:
  export NODEBREW_ROOT=/usr/local/var/nodebrew

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/nodebrew/1.0.1: 8 files, 38.6KB, built in 18 seconds
Removing: /usr/local/Cellar/nodebrew/0.9.6... (8 files, 37.9KB)
```

これでアップデート完了

続けて最新の安定板をインストール

```
$ nodebrew install-binary stable
Fetching: https://nodejs.org/dist/v12.6.0/node-v12.6.0-darwin-x64.tar.gz
######################################################################## 100.0%
Installed successfully
```

普段から頻繁にアップデートする人には当たり前かもしれませんが、nodeのバージョン頻繁に切り替えたりhomebrewのアップデート全然していないので（homebrewの意味）

ただの備忘録です、、、（
ESPとサーバ時間を使って、朝に処理させたい。

#やりたいこと
ESPやarduinoなどで、指定した時間(早朝に水やりなど)でウェイクアップして処理させたいことは、よくあると思う。
でも、指定した時間分だけスリープすることは出来るが、どれだけスリープするかなので、何時に起動するというのは難しい。
規則正しくスリープさせても実時間を取得しない限りはどんどんずれていくでしょう。
(宇宙飛行士はどうやって時計を合わせるか。)

そこで、サーバに起動したい時間をリクエストしておき、サーバからは、あとどれだけ眠ればいいのかを貰い、その時間を使って仕事の時間まで眠りに入るようにします。そうすれば、繰り返したとしても、起きたときは調度よい時間が保てるはずです。

#サーバ処理
まずは、簡単にrubyで書きます。
今回の仕様では、毎日ウェイクアップする前提で、次の時間までの秒数を返すようにします。
デーン。

```Ruby
wakeup = "14:50"
( 86400 -( Time.now.to_i - Time.parse(wakeup).to_i) ) % 86400
```

86400は1日秒です。指定した時間で差分を取ってはみ出したら、指定時間をはみ出しているので、残り時間を出します。はみ出していなかったら、１日秒をごっそりとって、残り時間を出します。(TODO:分かり易さ)

rubyで書いておいて何ですが、サーバを用意するのが面倒なので、google cloud functionsに実行させます。
なので、nodejsに書き換えます。

そして、インラインエディタのindex.jsに書きます。デーン。
少し長くなりましたが、やりたいことは同じです。

```js

/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
exports.wakeup = (req, res) => {
  let waketime = req.query.waketime || req.body.waketime || "07:01";
  let hours = waketime.split(":")[0];
  let minutes = waketime.split(":")[1];
  let dt = new Date();
  let now = Math.floor( dt.getTime() / 1000 );
  dt.setHours(hours,minutes);
  let time = Math.floor(dt.getTime() / 1000 );
  let result = ( 86400 - ( now - time) ) % 86400 ;
  res.status(200).send(String(result));
};
```

あと、タイムゾーンが海外時間なので、cloud functionsの環境変数に、```TZ Asia/Tokyo```をセットして、デプロイすれば完了ですね。
これで、ESPからhttpリクエストでパラメータに?wakeup=7:17とかにすれば眠る秒数が返ってきます。

#ESP処理

ここからは、まだ確認中ですが、ESPのディレイでは1日程度であれば、unsigned long が使えるので、

```c
delay(strtoul(wakeupdelay) * 1000);
```
と、すればできるのではないでしょうか。
追記：

```
delay(strtoul(wakeupdelay.c_str(),NULL,10) * 1000);
```
Stringで取得できるので、これでできました！

#おわりに
もちろん通常であれば、ボタン電池と時計モジュールを追加で作成するのでしょうが、追加コストも掛かるので、
Wifiが使えて、電池を抑えたい場合には、今回の方法は有用じゃないかと思います。
O365とオンプレExchange間の空き時間参照と予定表共有の通信要件

ハイブリッド環境でOutlookの空き時間参照と予定表の共有は利用に必要な通信要件が異なる

#本件の環境
Exchange2010CAS/HUB
Exchange2010MBX(ユーザーメールボックスあり）
Exchange2013HUB/CAS(ハイブリッド、ユーザーメールボックス無し)
Office365

#前提の通信要件(共通)
O365とオンプレExchangeのハイブリッド構成でフェデレーション信頼を構成する事が必要となる。
そのために、以下の構成が必要
・全てのExchangeサーバーにおいて、[Exchange Online]と[Microsoft 365 Common および Office Online]の全ての必須項目について外部へ通信できる事
・外部からアクセス先のExchangeサーバー(Hybridサーバー）に対して、[Exchange Online]と[Microsoft 365 Common および Office Online]の全ての必須項目について外部から通信できる事
・O365から外部EWSのアクセス先(ExternalURL)は組織内のExchangeで統一する

Office 365 の URL と IP アドレスの範囲
https://docs.microsoft.com/ja-jp/office365/enterprise/urls-and-ip-address-ranges

#空き時間の参照
空き時間情報の参照とは・・・スケジュールアシスタントでの空き時間や予定の参照
1.O365からオンプレサーバーへの通信経路・・・参考URLを参照
※本環境ではO365からHybridサーバーに対して前提の通信許可が必要
2.オンプレからO365への通信経路・・・クライアントPC→Exchange2010CAS→O365
※2010CASからO365への通信を許可する必要がある
※Exchangeからプロキシ経由でO365を通信する場合は、Set-ExchangeServer -server <CASサーバー名> -InternetWebProxy <プロキシのURL>設定が必要

#予定表の共有
予定表の共有とは・・・招待メッセージ(sharing Invitation)を送付して他人の予定を開く方法
1.O365からオンプレサーバーへの通信経路・・・参考URLを参照
※本環境ではO365からHybridサーバーに対して前提の通信許可が必要
2.オンプレからO365への通信経路・・・クライアントPC→Exchange2010MBX→O365
※2010MBXからO365への通信を許可する必要がある
※Exchangeからプロキシ経由でO365を通信する場合は、Set-ExchangeServer -server <MBXサーバー名> -InternetWebProxy <プロキシのURL>設定が必要

#その他注意
・EWSのExternalURLの変更は2-3時間反映に時間がかかる場合がある
・Outlookの予定表のユーザーアクセス権が無いと参照できないため、必要な権限を付与する
・Outlookの予定表を開く、は予定表共有とは別物。クライアントから直接Office365に接続する動作となる。
※環境によっては動作しないため、Microsoftでは正式にサポートしていない

参考:Exchange Server ハイブリッド環境における予定表の共有について
https://blogs.technet.microsoft.com/exchangeteamjp/2017/10/31/sharing-calendar-in-hybrid-enviroment/
【Vue.js】v-forの完了後のイベント定義


# ポイント

DOMの更新後にイベントを実行する。

[▶ 公式リファレンス：Vue.nextTick( [callback, context] )](https://jp.vuejs.org/v2/api/index.html#Vue-nextTick)


```javascript:nexttick.js

this.$nextTick(() => {
       //処理
});

```

# 例

```vuejs:v-for.vue

<template>
<!-- v-forでリスト作成 -->
<ul>
  <li v-for=" item in items">{{ item }}</li>
</ul>
</template>

<script>
export default {
  data() {
    return {
       items: []
    }
  },
  mounted() {
    for(let i = 0 ; i <= 5 ; i++) {
       this.items.push(i);
    }
    //--- ※v-for完了イベント
    this.$nextTick(() => {
       alert('done');
     });
  }
}
</script>

 ```
JFreeChart-PolarChart-極座標-特定データを強調する


目次 ⇒ [JFreeChartサンプル](https://qiita.com/artery/items/3e9c63e5c14a9e965c97)

```java
package jp.avaj.lib.chart;

import java.awt.BasicStroke;

import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PolarPlot;
import org.jfree.chart.renderer.DefaultPolarItemRenderer;
import org.jfree.chart.renderer.PolarItemRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import jp.avaj.lib.algo.ArUtil;

/**
■ JFreeChart-PolarChart-極座標-特定データを強調する

・(1)データセットはXYSeriesCollectionを使う.
・(2)データには角度と値を指定する.
  ・角度はラジアンではなく度.
・(3)レンダラはDefaultPolarItemRenderer.
・軸は一つだけ必要で、NumberAxisを指定した.
・プロットはPolarPlotというものがあるので、これを使う.

 */
public class Chart20_01 {
  // PolarChar/極座標.
  A_Chart20 a_Chart20;
  // 目次-Artery-JFreeChart用のライブラリ
  A_Chart00 a_LibChartSampeContents;

  public static void main(String[] args) {
    XYSeriesCollection dataset = new XYSeriesCollection(); // (1)
    XYSeries data0 = new XYSeries("data0");
    data0.add(0.0D, 2.0D); // (2)
    data0.add(90.0D, 13.0D);
    data0.add(180.0D, 9.0D);
    data0.add(270.0D, 8.0D);
    dataset.addSeries(data0);
    XYSeries data1 = new XYSeries("data1");
     data1.add(90.0D, 0.0D);
    data1.add(180.0D, 22.0D);
    data1.add(250.0D, 18.0D);
    data1.add(355.0D, 10.9D);
    dataset.addSeries(data1);
    //
    DefaultPolarItemRenderer renderer = new DefaultPolarItemRenderer(); // (3)
    NumberAxis radiusAxis = new NumberAxis(); //(4)
    PolarPlot polarPlot = new PolarPlot((XYDataset)dataset,(ValueAxis)radiusAxis,(PolarItemRenderer)renderer);
    JFreeChart jfreeChart = new JFreeChart("PolerPlot",(Plot)polarPlot);
    //
    ChartFrame cFrame = new ChartFrame("PolerPlot",(JFreeChart)jfreeChart);
    cFrame.pack();
    cFrame.setVisible(true);
    // 特定データ(data1)を強調する
    {
      // 目で確認するために少し休む
      ArUtil.sleep(2000);
      // Bデータのインデックスを取得する
      // Datasetに挿入した順番でよいが、インデックスを改めて取得する方がよい
      int index = dataset.getSeriesIndex("data1");
      // 線幅を三倍に太くする
      renderer.setSeriesStroke(index,new BasicStroke(((BasicStroke)renderer.getBaseStroke()).getLineWidth()*3));
      //
      // 目で確認するために少し休む
      ArUtil.sleep(12000);
      // 元に戻す
      renderer.setSeriesStroke(index,null);
    }
  }
}

```
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278568/29a37be0-d873-52cc-c45d-9c63714ae2b5.png)
ローカルでのkubernetes構築がめっちゃ楽にできた件

kubernetes(k8s)のマネージドサービスは触ったけど実際にモノホンを触りたい。。。と思った時にローカルでkubernetesを構築しようと思ったら思いの外簡単だったのでまとめた。

## そもそも選択肢は?
- MicroK8s
    - 有力候補。。。と思ったらubuntuのみ(snapパッケージ)
    - 資料も豊富だが一旦他をみてみる
- k3s
    - めちゃくちゃ軽い
    - ただ開発用ならMicroK8sのがよさげ
    - エッジとか考えるならこれでもいいかも
- minikube
    - これも有力候補
    - 構築楽そう。。。だが今回は置いとく
- Docker for mac(windows)
    - 今回の主役
    - Docker入れるだけでいい
    - 導入が簡単 = とっつきやすい = 共有もしやすそう

という訳でDocker for mac(windows)で構築していきます。

## 構築
今回はMacで構築します。(Windowsでもやってる記事はみたので大丈夫なはず)

- Docker for macをinstallと起動
    - [ここ](https://docs.docker.com/docker-for-mac/install/)か、普通にhomebrewで入れます。
    - 困ったらdocker mac installとかでググってください。めちゃくちゃ親切な記事がたくさん出てきます。
- k8sの有効化
    - macのメニューバーのDockerアイコン→Preferences..→kubernetes→Enable Kubernetesにチェック
        - 起動にはそこそこ時間かかります。
    - k8sが立ち上がったら、macのメニューバーのDockerアイコン→kubernetes→docker-for-desktopに変更
        - minikubeとかが入ってるとkubectlの向き先がそっちを向いちゃうかもなので
- 一応確認
    - `kubectl get nodes` 
    <img width="501" alt="スクリーンショット 2019-05-04 4.34.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92883/33bc1da2-fc6a-0482-6e7e-42a680e9204d.png">
        - こんな感じに出るはず
- これで構築終わり！！めっちゃ簡単やん！！

## 試しにデプロイしてみる
- お手軽に入れれる、kubernetes-dashboard
    - https://github.com/kubernetes/dashboard
    - read meに従ってデプロイ
    - 2019/07/20時点では以下コマンド
        - `kubectl apply -f kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml`
        - `kubectl proxy`
        - ほんで http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ にアクセス
        - 認証云々言われたので[ここ](https://qiita.com/h-sakano/items/79bb15f7a0661e141c75)を参考にさせていただきました。
        - 認証が正常に終わるとこんな感じに
        <img width="1436" alt="スクリーンショット 2019-05-04 4.41.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92883/61ffcfde-1378-0f0f-16c2-12bc41f3e4f6.png">
ちゃんとできてる。。。簡単や。。。。

## まとめ
構築までこの手軽さなのでちょっと触ってみたいなーっという人にもオススメできると思います。
今回触らなかったminikubeやMicroK8sも触ってみたくなりますね。
次は構築難度や機能の比較などを作ってみようか。。。

### 諸々のversion
macOS: 10.14.5
DockerCE: 2.0.0.3
DockerEngine: 18.09.2
Kubernetes: v1.10.11
HBaseにThriftでRubyからアクセスしたい

## やりたいこと
HBaseにThriftでRubyからアクセスしたい。（表題ママ）

もともとHBaseにREST API経由でアクセスするRubyプログラムを書いていたのですが、Thriftでのみサポートされている操作を行いたかったのでThrift経由でアクセスするRubyのHBaseクライアントとそれを利用したプログラムを作ります。

## 書いた動機

- ThriftでHBaseにアクセスする処理をRubyで実装した例が見つからなかったので。
- Thriftがなんなのか分からない状態から、なんとなく分かった状態になれたので記念に。

## 環境
以下環境で確認しました。

- MacBook Air (13-inch, Early 2015)
- Ruby 2.4.0
- Amazon EMR HBase 1.3.1
  - 今回はEMRを使用していますが、ローカル環境に立てたHBaseサーバーでも構いません。

## 概要

1. Thriftをインストールする。
2. thrift gem を追加する。
3. HBaseクライアントのコードを生成する。
4. HBaseからデータを取得するコードを書く。

## 詳細

### 1. Thriftをインストールする。

brewだと一発で入りました。

```
brew install thrift
```

### 2. thrift gem を追加する。

```
gem install thrift
```

### 3. HBaseクライアントのコードを生成する。

thriftコマンドを使ってHBaseクライアントを生成します。

```
## HBaseのコードを取得 & 展開
wget http://ftp.riken.jp/net/apache/hbase/stable/hbase-1.4.10-src.tar.gz
tar zxvf hbase-1.4.10-src.tar.gz

## ソースコードの生成
thrift --gen rb hbase-1.4.10/hbase-thrift/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift

```

- 筆者環境ではthriftコマンドを実行すると、 `[WARNING:/path/to/hbase-1.4.10/hbase-thrift/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift:89] The "byte" type is a compatibility alias for "i8". Use "i8" to emphasize the signedness of this type.` というWARNINGが出ました。`HBase.thrift` の89行目にある `byte` を `i8` に書き換えて再実行したらうまくいきました。（これで良いのかは不明です :smiley: ）
- `gen-rb` というフォルダが作られ、その中に `hbase.rb`, `hbase_constants.rb`, `hbase_types.rb` の3ファイルが作られたらOKです。あとはこのファイルを使ってHBaseにアクセスするだけです。

### 4. HBaseからデータを取得するコードを書く。

Thriftで生成したをコードを利用するコードを書きます。

```main.rb
require './hbase'
require './hbase_constants'
require './hbase_types'

transport = Thrift::BufferedTransport.new(Thrift::Socket.new('hbase-host', 9090))
protocol = Thrift::BinaryProtocol.new(transport)
client = Apache::Hadoop::Hbase::Thrift::Hbase::Client.new(protocol)
transport.open()

# ネームスペース'test_name_space', テーブル'sample_table'の先頭から降順で10件取得する。（=末尾10件を取得する。）

scan = Apache::Hadoop::Hbase::Thrift::TScan.new
scan.reversed = true
scanner_id = client.scannerOpenWithScan("test_name_space:sample_table", scan, nil)
result = client.scannerGetList(scanner_id, 10)

result.each { |row_result| puts row_result.row }

transport.close()
```

- resultには `Array<::Apache::Hadoop::Hbase::Thrift::TRowResult>`が返ってくるので、あとは好きなように加工してください。
- 上記例では `Apache::Hadoop::Hbase::Thrift::TScan`を用いて、逆順のオプションを指定していますが、 `startRow`, `stopRow`などの指定も可能です。指定できるオプションは `hbase_types.rb` にある `TScan` クラスの定義 を見てみるとわかると思います。

実行結果は次のようなイメージです。

```
$ ruby main.rb
rowKey9
rowKey8
rowKey7
rowKey6
rowKey5
rowKey4
rowKey3
rowKey2
rowKey1
rowKey0
```

最終的なフォルダ構成は次のようになりました。

```
gen-rb
├── hbase.rb
├── hbase_constants.rb
├── hbase_types.rb
└── main.rb
```

## 終わりに

まとまったドキュメントを見つけきれず１日かけて手探りで実装していきましたが、あとから振り返ってみると1時間で終わりそうな内容でした。 :raised_hands:

## 参考
https://thrift.apache.org/tutorial/rb
なるはや Vue SPA入門：Bootstrap

Vue CLI3 で作成した SPA（Single Page Application）プロジェクト上で、段階的に Vue.js を学んで行きましょう。

[目次はこちら](https://qiita.com/tsubo/items/24df49ef2f1ba87984d1)

今回は Bootstrap 編です。

## 前提事項

[Vue.js devtools 編](https://qiita.com/tsubo/items/d03ef6aa7ca187527860) が完了していること。 

## Bootstrap

[コンポーネント編](https://qiita.com/tsubo/items/745324a9f4719cb6b8fa)で作成した TODO リストに、CSS のフレームワークである Boostrap を適用してデザインを変更してみます。

まずは bootstrap 関連のコンポーネントを追加します。

```bash
yarn add bootstrap jquery popper.js
``` 

main.js で bootstrap を import します。

```js:main.js
import "bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
```

TodoInputText.vue の input タグを以下のように修正します。

```vue:TodoInputText.vue
<template>
  <!-- class の指定を追加 -->
  <input
    type="text"
    class="form-control"
    v-model="value"
    @change="onChange($event.target.value)"
    placeholder="Add Todo"
  >
</template>
```

TodoListItem.vue の button タグを以下のように修正します。

```vue:
<template>
  <li>
    {{ todo.text }}
    <!-- class の指定を追加 -->
    <button
      class="btn btn-light btn-sm"
      @click="$emit('remove', todo.id)"
    >x</button>
  </li>
</template>
```

以下のようにボタンとテキスト入力項目のデザインが変わりました。

![bootstrap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14476/23eaac70-801e-8bf8-d593-068bdbd27ed0.png)

## 次回

[Vuex](https://qiita.com/tsubo/items/af3886cdbeb6781e7d52)
VSCodeでエディタ画面とターミナル間のフォーカスを楽して移動したい


マウスクリックで移動していたのですが、あまりにも非効率だったので何かないかと調べてみました。デフォルトではこれに相当するキーバインドが定義されていないため、自前で定義する必要があります。

`Ctrl` + `` ` `` で、エディタとターミナルのフォーカスを往復するようなキーバインドを定義したら捗るようになったので、シェアしようと思います。

## やり方

`Commend` + `Shift` + `p` でQuick openを開き、 `Preferences: Open Keyboard Shortcuts (JSON)` を選んでください。

Jsonの中身は以下のGistをコピペ。

https://gist.github.com/hassaku63/9ddde639088716e63efb8e319fbee4d1

以上。

`when` で、割り当てたキーバインドが押下された場合の発火(?)条件を制御しています。異なるフォーカスの移動に同じキーバインドを割り当てていますが、whenの指定によって重複を回避しています。ここでは

- ターミナルにいる場合はエディタに移動
- エディタにいる場合はターミナルに移動

としています。whenで定義できる内容については、公式の以下のセクションを参照ください。

https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts

JSONじゃなくてGUIで設定することもできますので、その場合はQuick Openで `(JSON)` が入ってない方を選んでいただければOKです。

## 参考
https://stackoverflow.com/questions/42796887/switch-focus-between-editor-and-integrated-terminal-in-visual-studio-code
OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens

[OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens (Draft 15)](https://tools.ietf.org/id/draft-ietf-oauth-mtls-15.html)に関するざっくりとしたまとめ

##### 2 Mutual TLS for OAuth Client Authentication

- OAuthのクライアント認証にTLSのクライアント認証を使う。
- クライアント証明書は、CA局を利用する方法（2.1 PKI Mutual TLS Method）と、自己署名証明書を事前登録する方法（2.2 Self-Signed Certificate Mutual TLS Method）がある。

##### 3 Mutual TLS Client Certificat-Bound Access Tokens

- アクセストークンをTLSクライアント認証で提示された証明書と紐付けて発行し、トークン使用時も同じ証明書でのTLSクライアント認証を課すことでトークンを利用者を制限する。
- トークンと証明書の紐づけは、証明書のハッシュ値をアクセストークンに埋め込む方法（3.1 JWT Certificate Thumbprint Confirmation Method）とToken Introspectionで取得できるようにする方法（3.2. Confirmation Method for Token Introspection）がある。

##### 4 Public Clients and Certificate-Bound Tokens

- Public Clientに対して、TLSクライアント認証をOAuthクライアント認証ではなく、トークンと証明書の紐づけのみに使うことができる。
- クライアントは自己署名証明書を作成しTLSクライアント認証で提示する。認可サーバーはクライアント証明書のCA局の検証はせずにトークンにのみ紐づける。
Atom HelperがPCのリソースを食い潰した際の対処法

## 概要
AtomのHelperはエディタの扱い方や不具合により、PCのリソースを食い潰すことがあります。
Atom HelperにPCのリソースが占有されると、PCはフリーズ状態に陥り、詰むことになるかもしれません:relaxed:
ということで、対処法をメモ。
![スクリーンショット 2019-07-19 1.30.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269537/39b3a4b1-d7bd-8ea6-c5d8-6f4482ce665c.png)

## 対処法
### 1. Atomを終了させる。
まず、Atomを終了させる。
ハングやフリーズによりどうしても通常終了が無理な場合、強制終了する。。。
状況によっては、PC自体を強制終了するコースになるかも。

### 2. Atomをセーフモードで起動する。
Atomが終了できたらターミナルから```atom --safe```を実行し、Atomをセーフモードで起動する。

### 3. キャッシュを消去する。
ターミナルから```rm -rf ~/.atom/storage```を実行し、キャッシュを削除する。
※キャッシュの場所をカスタムしている方は注意。

### 4. Atomを再起動する。
キャッシュを削除したらAtomを終了し、通常起動する。
動作に問題なければ(重くなければ)OK。
※念のため、アクティビティモニターやタスクマネージャーからリソースの利用状況を確認しておくといい。
yarn install時にnode-9.4.2.tgz取得が404 Not Foundで失敗した

# ちょっと古いプロジェクトをcloneしてyarn installしたらエラーが発生した

## 実行ログ

```bash
$ yarn install
yarn install v1.15.2
[1/4] :mag:  Resolving packages...
[2/4] :truck:  Fetching packages...
error An unexpected error occurred: "https://registry.yarnpkg.com/@types/node/-/node-9.4.2.tgz: Request failed \"404 Not Found\"".
info If you think this is a bug, please open a bug report with the information provided in "/Users/watanabe-yohei/work/repos/user/dojin.user/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
```
node-9.4.2.tgzが404 Not Foundとのこと

## 一応yarn-error.logも確認

Trace抜粋

```
Trace:
 Error: https://registry.yarnpkg.com/@types/node/-/node-9.4.2.tgz: Request failed "404 Not Found"
     at ResponseError.ExtendableBuiltin (/usr/local/Cellar/yarn/1.15.2/libexec/lib/cli.js:696:66)
     at new ResponseError (/usr/local/Cellar/yarn/1.15.2/libexec/lib/cli.js:802:124)
     at Request.<anonymous> (/usr/local/Cellar/yarn/1.15.2/libexec/lib/cli.js:66128:16)
     at Request.emit (events.js:197:13)
     at Request.module.exports.Request.onRequestResponse (/usr/local/Cellar/yarn/1.15.2/libexec/lib/cli.js:130418:10)
     at ClientRequest.emit (events.js:202:15)
     at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:560:21)
     at HTTPParser.parserOnHeadersComplete (_http_common.js:113:17)
     at TLSSocket.socketOnData (_http_client.js:447:20)
     at TLSSocket.emit (events.js:197:13)
```

やっぱりnode-9.4.2.tgzが404 Not Foundとのこと

## アクセスしてみてもNot Found
https://registry.yarnpkg.com/@types/node/-/node-9.4.2.tgz

```
{"error":"Not found"}
```

node-9.4.2.tgzは死んだ。

# yarn.lockが原因

## 前提としてyarn installについてざっくり説明
`yarn install`コマンドは`package.lock`に書かれているモジュールの常に最新を取ってくるが、 `yarn.lock` がある場合、`yarn.lock`に記載されたバージョンを取得する。
これによりバージョンの差異で挙動が違うなどの発生を低減できる、が、今回のような「期待するパッケージが失せてyarn install失敗」みたいなことが起こる。更新のプルリクを投げよう。

## 今回のyarn.lock

抜粋

```
"@types/node@*":
 version "9.4.2"
 resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.2.tgz#b109a6c4f64147ccf9476d39e1a6bfds9aa0faeb8"
```

# 対応

## yarn.lockを削除して、yarn install

もしnode_modulesがあれば、それも消しておいた方がyarn installの邪魔をしない（気休め）

```bash
$ rm yarn.lock
$ rm -rf node_modules
$ yarn install
~略~
success Saved lockfile.
:sparkles:  Done in 29.33s.
```

successになればOK

# 参考
- [An unexpected error occurred: "https://registry.yarnpkg.com/<package>: Not found" #5865](https://github.com/yarnpkg/yarn/issues/5865)
VM環境で作るJavaアプリ開発環境編

# 背景
いつもはWindowsでJavaとTomcatをEclipseで設定して作業しているが
今後仕事で仮想環境で環境面を統一するときがあるかもしれないと思い、
Javaでも実施してみたくなった

# 目的
業務効率化

# tomcat バージョン
> 以下の参考で提示されているのだと404になったため以下から取り直しました。

[http://ftp.kddilabs.jp/infosystems/apache/tomcat/tomcat-7/v7.0.94/bin/](http://ftp.kddilabs.jp/infosystems/apache/tomcat/tomcat-7/v7.0.94/bin/)

# 実施
1. 以下の参考リンクを試しているところです ←今ここ
2. EclipseとVMを紐づける
3. Spring導入

> 随時更新します。

# 参考
[https://qiita.com/cyubachi/items/47460f40ff4423182727](https://qiita.com/cyubachi/items/47460f40ff4423182727)
【Atcoder】DPまとめコンテスト M candies

こんばんは:runner:
今日は[DPまとめコンテスト](https://atcoder.jp/contests/dp/tasks/dp_m)のM candiesを解いてみようと思います！

##問題概要
*N*人の子供たちに*K*個のあめを配る。ただし子供*i*に配るあめは0以上*a<sub>i*個でないといけない。


##解法
*i*人目までの子供に*j*個のあめを配ることを考え、この場合の数を*dp[i][j]*とする。
この状態に*i-1*人目の状態から至るためには、以下からの遷移が考えられる。

 - *i-1*人目までに*j*個配る。*i*人目には0個配る。
 - *i-1*人目までに*j-1*個配る。*i*人目には1個配る。
 - *i-1*人目までに*j-2*個配る。*i*人目には2個配る。
 - （中略）
 - *i-1*人目までに*j-a<sub>i-1*個配る。*i*人目には*a<sub>i-1*個配る。

数式にすると

$ dp[i][j] = dp[i-1][j]+dp[i-1][j-1]+dp[i-1][j-2]+\cdots+ dp[i-1][j-a_{i-1}] \tag{1} $

式が長い！
この*j*に*j-1*を代入して書き換えます。

$ dp[i][j-1] = dp[i-1][j-1]+dp[i-1][j-2]+dp[i-1][j-3]+\cdots+ dp[i-1][j-a_{i-1}-1] \tag{2} $

*(1)*から*(2)*を引くとスッキリ。

$$dp[i][j] = dp[i-1][j]+dp[i][j-1]-dp[i-1][j-a_{i-1}-1]$$


##実装
```C++
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
typedef long long ll;
int n,k;
vector<ll> a;
ll dp[110][100010];
ll mod = 1000000007;

int main(){
 cin >> n >> k;
 a.resize(n);
 for(int i = 0; i < n; ++i) cin >> a[i];
 for(int i = 0; i <= n; ++i) dp[i][0] = 1; //i人目までに0個配る方法は1通り
  
 for(int i = 1; i <= n; ++i){
   for(int j = 1; j <= k; ++j){
     dp[i][j] = (dp[i - 1][j] + dp[i][j - 1])%mod;
     if(j - a[i - 1] - 1 >= 0){
       dp[i][j] = (dp[i][j] + mod - dp[i - 1][j - a[i - 1] - 1])%mod;
     }
   }
 }
 cout << dp[n][k] << endl;
 return 0;
}
```

DPは奥が深いですね:bride_with_veil_tone2:
RocketChatをCentOS(EC2)にInstallする　公開に漕ぎ着ける編

# 前段
[前回](https://qiita.com/yonex_memo/items/9d8ed5b1bcdd0d85f56d)EC2上に[Rocket.Chat](https://rocket.chat/)を導入したのですが、諸々気になる部分があるので
今回はその辺りを整理してなんとか検証できる環境を作りきりたいと思います。

# 気になること
**・サインアップ時に使用できるメールアドレスのドメイン制限**
**・メール送信経路（作った覚えもない)**
**・Anyで解放するこのドキドキ感を緩和する施策**

ということで上から行きます。

# サインアップ時に使用できるドメイン制限


[この辺](https://rocket.chat/docs/administrator-guides/account-settings/#registration)じゃなかろうかと思うのです。

> Allowed Domains List:
> This will block emails with different domains than the ones on this list.

あとこの辺りも有効にしておきたい気もする
> Email Verification: 
> If this is set to true, users will have to confirm their email via a confirmation email sent to their email. (For this setting work, the SMTP settings must be already set up. See Email Configuration)

・管理->アカウント->登録->許可されたドメイン一覧にドメインを登録します。
・同じところにメール認証の項目もありますがまだSMTPを設定していないのであとでやります

![あった.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90505/c6299b34-739c-db4b-8cff-9b1c49727f53.png)


# メール送信経路

・メール送信にはSESを利用(SMTP Auth)
・Postfixを挟んでSESにRelayした方が何かあった時に早い気もするけど、Rocket.ChatからSESを直接指定する
・SESはバージニア北部を使用
・送信元アドレス（今回は自分のアドレスを使用）は先に認証しておく
・SandBoxモードは解除しておく（少し時間がかかるのでテストメールは認証済みの送信元アドレスをFrom/Toで利用）
・SESのSMTP SettingからSMTP Authに利用するIAMユーザを作っておく
・プロトコルはSMTP、ポートはサブミッションポート、IgnoreTLSはいいえ
・ユーザ名パスワードはSMTPSettingで作成したIAMユーザのものを使用

![SMTPの.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90505/ded17f07-3cc6-ac65-dcd4-c723a96763e0.png)

・テストメール送信はうまくいったが
・届いたメールが「このメールにはご注意ください」になっている
・MAIL FROMはDomain:amazonses.comから変えていない
　→メールヘッダを見てもdkim=pass、spf=passになってる
・多分gmail側でgmailのSMTPかどうか、見てるんだと思う。きっと。わかんない。

# Anyで解放するこのドキドキ感を緩和する施策
・cognitoを挟む？
・AWS WAF入れる？
・ユーザビリティは下がりそうですが、一旦Cognitoで簡単な認証を設定してWAFを後から入れてみようと思います。

##cognito
・目的はあくまでも緩やかなブロック
・[素晴らしい記事](https://dev.classmethod.jp/cloud/alb-cognito-user-pool/)を参考に設定

**認証がきた**

![cognito.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90505/804f00d9-03b8-f4c8-d081-df60c54c6acd.png)

**初回パスワード変更**

![cognito2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90505/0c138dfd-a2e1-3eae-f74a-bc01256ad872.png)

**ログイン画面に遷移できました**

![ok.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90505/132328d7-9647-6a47-68c0-bcbab57d7274.png)

## あらためて、というか再認識
・画像ファイルを添付しながら丁寧に記事を書くのは本当に大変
・最初から粒度粗々だったけど途中からさらに粒度が落ちてしまった
・いつも何気なく読んでしまっている技術記事も同じ背景があるんだと思うと感謝せずにはいられない
・この記事が誰かのお役に立てば嬉しい。

#　参考
[・インフラエンジニアが一切コードを書かずにWebサーバーに認証機能を実装した話](https://dev.classmethod.jp/cloud/alb-cognito-user-pool/)