OmniAICreator/Qiita-1.07M huggingface dataset:
若手エンジニアに送る、"心構え"と"キャリア観"に行ってきました

t_wadaさんの講演に参加したメモ

「エンジニアとしてこの先生きのこるために」

内容
======

はじめに
------
「プログラマが知るべき97のこと(通称:きのこ本)」と「達人プログラマー」をベースの内容となっている
特に以下

 - プログラマが知るべき97のこと: 18番-学び続ける姿勢
 - 達人プログラマー:「常にあなたの知識ポートフォリオに投資すること」

学び方を学ぶ
-----
エンジニアの学び方5つ

### 1. 四半期ごとに技術書を読む(in 達人プログラマー)

> 3年続ければ"ついてくる" 
by t_wada先生
 
人間の記憶の仕組みを理解して"学ぶ"(=理解し自身に血肉にする)

 - 一度経験したものはどこかで覚えている、がたどり着かない
   - たどり着くには？→ **反復学習, 連想する**
 - 連想する方法 : その本の参考書籍を読む→数珠つなぎに読んでいく
   - その本は前提としてどんな知識があるのか、そのときにあの技術は存在したのか→**連想**
 
 
### 2. 手を動かして学ぶ

できるからやるではない
**やる(反復)　から できる 、できる から 好きになる**
 
「デールの円錐」

 - 受動学習 < 能動学習が圧倒的に学習の強度が高い
 - エンジニアにおける能動学習とは？　→ **「写経」**
    - https://twitter.com/t_wada/status/9000231741
 - これだと思った本に定めて行う


### 3. 毎年少なくとも1つの言語を学習する
*「常にあなたの知識ポートフォリオに投資すること」*にコミットする行動

 - まずは仕事で使うもの、終わったら仕事で使わないであろうパラダイムの言語を手を付ける
 - パラダイムを複数変えるのは挫折する、1つに絞って行う
    - 何が起こるか → 他者(他パラダイム)を知るから今までを理解できる
 - 流行るであろうものをキャッチし学ぶ(学んだことが無駄にならないよう)
    - 第三者評価を読み解く https://www.thoughtworks.com/radar

 - 英語できるだけでi/oの質量共に増える


### 4. 身の回りをプログラミング対象にする
*「常にあなたの知識ポートフォリオに投資すること」*にコミットする行動

 - 自分の好きな道具で自分のしたいことを作る

### 5.アウトプットを行う
 - 能動学習は効率よくインプットすることに寄与する
 - **情報を発信するひとに人は集まる、集まるとインプットが増える**
 - **量は質に転化する**
 - 質が悪いから、、とアウトプットを止めなくていい、批判する人間はどこでもいる、気にせずやっていこう
    - エラーメッセージそのまま貼り付けて試行錯誤しただけでも価値がある
    - 作者がありがたい/他の同じハマった人がありがたい
 - 手法
    - twitter/ブログ/コード公開/講演する/ライブコーディング


現役プログラマでいるために
-----

1. 毎日コードを書く(Write Code Every Day)
 - 恩恵
  - 必要最小限のコードへの集中
   - 進んでいるという実感
   - バックグラウンド処理 ... PCの前じゃない
   - コンテクストスイッチ少ない ... 週末のみだと思い出すのに時間がかかる
   - **ワークライフバランス向上** ... 仕事生活自分のバランスのとり方がわかってくる
   - 周りからの理解

2. 年下から学ぶ
 - できること⇔好きになる のラーニングループが少ないと、それ自体が市場になくなってくる→周りから見たら老害になる
 - **自分が持っていない他者のラーニングループを見ることができる**

3. 過去から未来を学ぶ
 - 技術は「らせん」
   - 今もいつかは廃れる
 - T字型でなく複数の柱を持つ

4. 人の作る渦をみる
 - 個が多く集まると何かが起こる
    - githubインパクト
 - 意思決定の違いを見抜いて選択する
    - エコシステム指向 : 中心部がレッドオーシャン, 混沌としていて安定したモノがない 
        -  ex)フロントエンド
    - ロードマップ指向 : 一本の強固なモノがある
        - ex)iOS開発(🍎と違う方向に進むとダメになる)
    - https://twitter.com/t_wada/status/982155252643250177

5. 大事なことに集中する
ライフステージによって時間が変わる


質問時間
------
 - 言語学習においてどこまでやって「学習した」というのか
   - パブリック・プライベートにかかわらず動くものができた
 - 毎日コード、持続させる方法
    - 1人になる割り込みのない安定した時間をコントロールする
    - "小さなことにイラつく"
 - 働き方を変更する意思決定はどのようなものか
    - **アウトプットによって選択肢がでてくる**
 - ペアプロの対象シーンはどのように選定すればよいか
    - 費用対効果が高いところに
        - 新卒
        - 不具合修正
    - fearless change (大きい組織に対して恐れを緩和して変化を促すか)
 - 柱が折れそうなときは柱を折るほうに移るのか
    - 基本的に完全に折れることはない
    - 対抗馬は折れるかを考える、前のらせんのときの類似を考え、メリデメを見る
 - 体調管理で工夫していること　
    - 良いディスプレイを使う
    - 自作キーボード
    - 椅子、いい椅子
    - ロールモデルを見つける
 - ライフとして子育てを選択した経緯があれば
    - 大前提としては授かりもの
        - 周りに同じような立場の人がいたのでライフハックがわかっていた
        - 準備ができていた（柱の確立ができていた)

所感
======
~~らいおんのひとりあるき...くだりが楽しかった~~

突き詰めれば脳の学習モデルに即してシンプルだなあと改めて思いました。  
ただそれはわかっても具体的な行動の指針がわからなかったところを、とてもわかり易くお伝えしていただけてありがたかったです。
すごいH本読んだからまとめ 5 「再帰」

## はじめに

* [すごいHaskellたのしく学ぼう](https://www.amazon.co.jp/%E3%81%99%E3%81%94%E3%81%84Haskell%E3%81%9F%E3%81%AE%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%BC%E3%81%86%EF%BC%81-%EF%BC%AD%EF%BD%89%EF%BD%92%EF%BD%81%EF%BD%8E%EF%BC%AC%EF%BD%89%EF%BD%90%EF%BD%8F%EF%BD%96%EF%BD%81%EF%BD%83%EF%BD%81-ebook/dp/B009RO80XY)を読んだのでちょっとずつまとめていきたい。まとめていきたい。

* シリーズ
  * [すごいH本読んだからまとめ 1 「関数の呼び方、関数の定義の仕方」](https://qiita.com/yumakkt/items/ce82eb3ffae874faf249)
  * [すごいH本読んだからまとめ 2 「リスト,タプル」](https://qiita.com/yumakkt/items/36d95c738a3bc17119bd)
  * [すごいH本読んだからまとめ 3 「型」](https://qiita.com/yumakkt/items/f47e8ee810679978869f)
  * [すごいH本読んだからまとめ 4 「関数の構文」](https://qiita.com/yumakkt/items/c50dcd286cf7521e31a0)

## 再帰

+ Haskellにfor文はない模様（基本的には変数の状態変更を扱わないんだからいらないよねって感じ）
+ for文っぽいことやりたかったら`再帰`, `fold`, `内包表記`を使えば大抵のことは実現できる
+ 今回は再帰について

### そもそも再帰とは

* 関数定義のときに`ある条件で自分自身を呼び出す`こと。
* 関数内で自分自身が関数としてよばれると`再帰的呼び出し`とかいう

例

```haskell

-- 再帰の話になるとよく例題にされる関数
-- factorialは階乗
-- 5の階乗は 「 5! = 5 * 4 * 3 * 2 * 1 = 120 」となる
factorial' :: (Integral n) => n -> n
factorial' 0 = 1
factorial' x = x * factorial' (x-1) -- 自分自身を呼び出す。

*Main> factorial' 5
120

```

### `基底部`と`再帰部`

* 再帰関数には`基底部`と`再帰部`がある
* 再帰部は`繰り返し自分自身を呼び出す`部分
* 基底部は`これ以上再帰しない`で一定の値を返す部分

例

```haskell

-- さっきの関数で基底部と再帰部を確認

factorial' :: (Integral n) => n -> n
factorial' 0 = 1 -- 基底部
factorial' x = x * factorial' (x-1) -- 再帰部

*Main> factorial' 5
120

```

* 下記の通り再帰関数の値は決まる
  1. 再帰部を積み重ねる
  1. 基底部が決定する
  1. 再帰部の値積み重なった再帰部の値が決定していく
* 複数の再帰部が存在する関数があったとしてそれは変わらない

### 再帰関数を作ってみる


#### replicate

ある数の分だけ、同じ値のリスト作成

```haskell
replicate' :: (Num i, Ord i) => i -> a -> [a]  
replicate' n x  
    | n <= 0    = []  
    | otherwise = x:replicate' (n-1) x 

```

#### take

与えられたリストから指定した数の分だけ取り出した新しいリスト作成

```haskell
take' :: (Num i, Ord i) => i -> [a] -> [a]  
take' n _  
    | n <= 0   = []  
take' _ []     = []  
take' n (x:xs) = x : take' (n-1) xs 
```

#### zip

２つのリストをタプルでまとめたものにする。リストの長さが違う場合は長い方の余ったリストは無視される

```haskell
zip' :: [a] -> [b] -> [(a,b)]  
zip' _ [] = []  
zip' [] _ = []  
zip' (x:xs) (y:ys) = (x,y):zip' xs ys 
```

#### quicksort

クイックソート、先頭の値より大きいものと小さいもので分けていく計算を再帰的に行う

```haskell
quicksort :: (Ord a) => [a] -> [a]  
quicksort [] = []  
quicksort (x:xs) =   
    let smallerSorted = quicksort [a | a <- xs, a <= x]  
        biggerSorted = quicksort [a | a <- xs, a > x]  
    in  smallerSorted ++ [x] ++ biggerSorted 

*Main> quicksort　[1, 3, 2, 5, 1, 9, 4, 7, 3]
[1,1,2,3,3,4,5,7,9]
*Main> quicksort　"vfdaiogfygrhyahvghakfhjhsgaf"
"aaaadffffgggghhhhhijkorsvvyy"
```
和田卓人　若手エンジニアに送る心構えとキャリア観

#自己紹介

### アカウント
github→　twada
### 書籍
プログラムマが知るべき97のこと
###
レビューをしていただける最低条件→テストコードを書いている
### 海外での立ち位置
power-assert javascriptのテストツール

### 話の下地
きのこ本で最も参照された本→達人プログラマー
"常にあなたの知識ポートフォリオに投資すること"

#学び方を学ぶ
リクルートテクノロジーズの研修






## 1. 四半期ごとに技術書を読む(何を読むか迷ったらいいと思った本の参照先をたどる)
### 記憶について
感覚記憶(0.5 ~ 2sec)
短期記憶(15 ~ 30sec)
長期記憶(死ぬまで？)
"忘れる" = 記憶は格納されているけどたどり着けない

- 記憶のピッカーを育てる＝反復練習（何度も長期記憶からとりだす）
- 連想する＝他の記憶とセットで。つながりを意識。→たとえば、本を時系列で並べる（railsの誕生によってどのような影響があったのかを意識すると誤読を防げる）


## 2. 手を動かして学ぶ
### まず始める
やる→できる→好きになる→できる→好きになる→、、、、
### デールの円錐
インプットよりもアウトプットした方が記憶が定着する
### 写経について
ほんたった
![IMG_7400.JPG](https://qiita-image-store.s3.amazonaws.com/0/299225/6c2fff1b-95f6-8f83-eccc-020b5eabae3b.jpeg)

## 毎年一つは言語を学習する
↑達人プログラマーの教え
駆け出しプログラマーは仕事で使う言語をマスターする。
その後は違うパラダイムの言語を学ぶ（静的、動的、オブジェクト指向、関数型、遅延評価）。ただし少しずつ変えていく。モダンな言語の方が改良が加えられている。

### 世の中の流れを知るには
technology radar(thought works)
### 英語は大事
特に読めるようにする

## 身の回りをプログラミング対象にする
プライベートの中でwebサイトを作ったりする
きのこ本でも、、
- markdownで書く
- git でバージョン管理



- アウトプットいていく人には情報が集まる。インプットとアウトプットの正のフィードバックループが生まれる。
- 社内、社外でアウトプットできる場を作る
- 量は質に転化する(陶芸のクラスにて量で評価するクラスから質の高いものが生まれた)
- ブログを書く  "情報発信は数学の証明ではなく料理のようなものである"
- 付加価値を与えるにはいつやったのか、何を参照したのか、エラーログをそのまま載せたりする。情報量を多くする。
- 文書だけでなくコードを公開する。海外ともつながりができる。
- ライブコーディング

# 現役プログラマでいるために
## 1. 毎日コードを書く
John Resig jQueryの作者
1. 毎日コードを書く
2. 意味のあるコードを書く。（リファクタリングはカウントしない）
3. 深夜24時には終了すること
4. OSSで公開する

進んでいるという実感が実際の進捗と同じくらい大事
アイディアはコードを書いている時以外に降りることが多い。常に考えるようにする。

###住む場所を工夫する
始発駅に住む→座れるからコードをかける

## 2. 年下から学ぶ
"一生プログラマーでいられるかどうかは年下から学べるか否か"
### ベンチマークとアンラーニング

## 3. 過去から未来を見る
技術は振り子ではなく螺旋　差分を見る・理解することが大切
「技術選定の審美眼」 speaker deck

T字型ではなく複数の柱を

## 4. 人の作る渦を見る
Githubによって組織から個人の時代に
### ロードマップ指向とエコシステム指向
エコシステム指向→中心部がレッドオーシャンで周辺部がブルーオーシャン
ロードマップ指向→iosの開発　アップルが舵取りしている

The Rise of "Worse is Better"(chasen.org)

## 5. 大事なことに集中する
書籍「エッセンシャル思考」


# 質問
### モチベーションが落ちる
頭の中にインデックスをつけることも大切
技術書は通読しなくても良い
人を巻き込む

### 言語学習のゴール
自分以外の人に使われる段階になったら

自分のブランディングができた後で仕事の質が変わった。
アウトプットすることで自分の専門が確立していった。勝手に仕事がやってくる。
情報発信する前は履歴書にスキルセットを書くみたいな感じだった。








Confluenceのエディターに機能を追加したいとき。。

Confluenceのページ編集機能は、TinyMCEのカスタマイズ版を使っています。
なので、機能を拡張するときはTinyMCEのプラグインとしてモジュールを追加するのがよさそうです。

init.rteをフックする方法を使った記事がありましたが、直接飛んだり、リロードすると呼ばれなかったりとちょっとはまりました。

[TinyMCE](https://www.tiny.cloud/)は、現在ver.5のデベロッパープレビューが出ていますが、手元のConfluence6.7.xでは、ver.3をカスタマイズしたものを利用していました。ドキュメントを見るときは注意が必要です。ver5のAPIと結構違いがあります。

ここ(https://developer.atlassian.com/server/confluence/enabling-tinymce-plugins/) に本家のチュートリアルがあります。

結局やることとしては...

web resourceに、`<dependency>editor<dependency>`と、以下のjsを読み込むようにしておく。

くらいで最低限のことはできそうです。

``` js
// プラグインの定義
define('プラグイン名', ['ajs', 'jquery'], function (AJS, $){
    "use strict";

    return {
        init : function(ed) {
            // ボタンを登録するグループを新規追加、既存のグループは、↑のリンクにある
            $("#rte-toolbar .toolbar-primary").append($("<ul class='aui-buttons'></ul>")
                .addClass("rte-toolbar-group-example"));

            // コマンドmceExampleの処理を記載
            ed.addCommand('mceExample', function() {
                // html片をカーソル位置に入れてみます
                tinymce.activeEditor.execCommand('mceInsertContent', false, '<h1>XXX</h1>');
            });

            // ボタンを登録
            ed.addButton('confluence-example-button', {
                title: "xxx", // アイコンだけ表示したければ、ブランクにしておく
                tooltip: "xxx",
                cmd: "mceExample",
                className: "example",
                icon: "aui-icon aui-icon-small aui-iconfont-addon",
                locationGroup: "rte-toolbar-group-example", // 上で作ったグループ名を指定
                weight: 0
            });
        },
        getInfo : function() {
            return {
                longname : 'Example',
                author : 'Atlassian',
                authorurl : 'http://www.atlassian.com',
                version : tinymce.majorVersion + "." + tinymce.minorVersion
            };
        }
    }
});

// 作ったプラグインを登録するおまじない
require('confluence/module-exporter')
    .safeRequire('プラグイン名', function(ExamplePlugin) {
        var tinymce = require('tinymce');

        tinymce.create('tinymce.plugins.ExamplePlugin', ExamplePlugin);

        // Register plugin
        tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin);

        require('confluence-editor/loader/tinymce-bootstrap').addTinyMcePluginInit(function(settings) {
            settings.plugins += ",example";
        });
    });
```
（書きかけの記事）Androidでファイル入出力

#この記事の概要
Androidでファイル入出力する方法について自分用にまとめます。

#基本

##Javaのファイル入出力の流れ
1.パスとファイル名を指定してFileインスタンスを生成します。
2.Fileインスタンスを引数にしてFileReader/FileWriterインスタンスを生成します。
　文字列を上書きするか追記するかを指定することができる。
　　FileWriterのコンストラクタの第二引数に
　　　trueを指定・・・「追記」
　　　falseを指定・・・「上書き」
3.FileReader/FileWriterインスタンスを引数にBufferedReader/BufferedWriterインスタンスを生成します。
4.BufferedReaderインスタンスのreadLine()メソッドで文字列を読み込みます。
BufferedWriterインスタンスのwrite()メソッドで文字列をファイルに書き込みます。
（すぐに書き込まれない可能性があるのでflush()メソッドを読んでおくと良い）
5.読み込み/書き込み終わったらclose()メソッドでファイルを閉じます。

##Androidのファイル入出力の流れ
基本的にはJavaのファイル入出力の流れと同じですが、項番1と2が異なります。
- ファイルオープンがFileクラスのコンストラクタではなく、ContextのopenFileOutput()メソッド、openFileInput()メソッドになります。
- 2がFileWriterではなく、OutputStreamWriterになる。

1.ファイル名を指定して上記のファイルオープンメソッド(openFileOutput()/openFileInput())を呼びます。
2.1で取得したFileInputStream/FileOutputStreamインスタンスを引数にしてInputStreamReader/OutputStreamWriterのインスタンスを生成します。
3.InputStreamReader/OutputStreamWriterインスタンスを引数にBufferedReader/BufferedWriterインスタンスを生成します。
4.BufferedReaderインスタンスのreadLine()メソッドで文字列を読み込みます。
BufferedWriterインスタンスのwrite()メソッドで文字列をファイルに書き込みます。
（すぐに書き込まれない可能性があるのでflush()メソッドを読んでおくと良い）
5.読み込み/書き込み終わったらclose()メソッドでファイルを閉じます。

```Java:読込サンプル
// FileInputStreamクラスはInputStreamクラスを継承しているため、InputStreamクラスで受け取るのが普通かも？
FileInputStream fileInputStream = openFileInput("FileOutputStream.txt");
bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"));
String lineBuffer = bufferedReader.readLine();
// 読込できた場合はメモリに保持する
while (lineBuffer != null) {
    stringBuilder.append(lineBuffer);
    // 次の行があれば、改行コードを挿入
    if ((lineBuffer = bufferedReader.readLine()) != null) {
        stringBuilder.append(BR);
    }
}

```

## ファイル出力
###ファイル出力の種類

- Android標準
- Java標準
    - FileWriter
    - BufferedWriter
        - FileWriterの拡張クラス
            - 特徴
                - newLine()メソッド・・・プログラムを実行している環境にあった改行コードを生成してくれる。
                - close()メソッド・・・BufferedWriterでクローズし、FileWriterではクローズしない。
    - PrintWriter
        - BufferedWriterの拡張クラス
            - 特徴
                - print()メソッド・・・write()メソッドは文字列しか引数に指定できないので、自前でString型に変換する必要があるが、print()メソッドはint型やboolean型の値も引数に指定することができる。
                - println()メソッド・・・print()メソッドの改行あり版（改行コードは環境に合わせた物を使用してくれる）
                - close()メソッド・・・PrintWriterでクローズし、BufferedWriterやFileWriterではクローズしない。

## ファイル読込
###ファイル読込の種類

- Android標準
- Java標準
    - FileReader
        - 特徴
            - read()メソッド・・・一文字ずつ読み込むため、普段使用することはない...。
    - BufferedReader
        - FileReaderの拡張クラス
            - 特徴
                - read()メソッド・・・一文字ずつ読み込む。
                - readLine()メソッド・・・一行ずつ読み込む。
                - close()メソッド・・・BufferedReaderでクローズし、FileReaderではクローズしない。
Expressを使ってhello world


https://expressjs.com/ja/
に、書かれているインストールとhello worldをするだけの簡単なお仕事。

## 環境
macOS Mojave ver 10.14

## express install

```
$ npm init
$ ls .
package.json
$ npm install express --save
$ ls .
node_modules
package-lock.json
package.json
```

## hello world

index.jsに以下の内容で書き込みます

```
const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(3000, () => console.log('Example app listening on port 3000!'))
```

その後、ファイルを保存し、閉じて

```
$ node index.js
```

とすると、http://localhost:3000/ にアクセスしてページが表示できるようになります。


簡単ですね。
全て開発者が学ぶべき "全ての開発者が学ぶべき～～言語" と "今後必要になる(ならない)～～言語"

今回の騒動には「どのプログラミング言語を使うべきか」という技術的観点や、現代や過去のプログラミング事情、また Qiita というプラットフォームにおける「高品質な記事とは何か」に関する考察など、有益なコンテンツが多数含まれていると思います。

一通り読んでみたかったので、私のように後追いの方でも簡単に追えるよう、リンク集としてまとめてみました。

# 全ての開発者が学ぶべき～～言語

## 全ての開発者が学ぶべき5つの言語
https://qiita.com/poly_soft/items/e89bc757596cfdfba784

- 翻訳記事
- Java, Python, JavaScript, C/C++, Scala

## 全ての開発者が学ぶべき1つの言語
https://qiita.com/outlandkarasu@github/items/a2243eb3adbe906ec30d

- D言語

## 全ての開発者が学ぶべき自然言語
https://qiita.com/Gaccho/items/e12e998b0a1788d55f5f

- 英語

## 全ての開発者が学ぶべき1つのNim
https://qiita.com/tlllune/items/4aafa56818c3c814939f

- Nim言語

# 今後必要になる(ならない)～～言語

## 今後必要になるプログラム言語
https://qiita.com/administrator1974/items/387aab2a42bf57e3b215

- 元ネタ
- 2018/11/10 現在は閲覧できない

ちなみに当時の様子は [はてなブックマーク - 今後必要になるプログラム言語](http://b.hatena.ne.jp/entry/s/qiita.com/administrator1974/items/387aab2a42bf57e3b215) などからおおよそ知ることができる。

## 「今後必要になるプログラム言語」にひたすらマサカリを飛ばす
https://qiita.com/alter/items/389dba835cccf4e54e11

- 元ネタ記事の何が問題であるかを具体的に指摘している
- コメント欄には、元ネタ記事が閲覧不可になった経緯（推測）が色々と書かれている

ちなみに 2018/11/09、Qiita 公式から見解が出ている。 [Qiitaでのアカウント停止に関する考えについて - Qiita Blog](https://blog.qiita.com/account-suspension-in-qiita/) を参照。

## 「今後必要になるプログラム言語」を読むに当たって
https://qiita.com/pik/items/1c95d69debee4aedffea

- 元ネタ記事を読むために必要な前提知識（ Java 黎明期の知識）に関する話

## 今後必要にならないプログラミング言語
https://qiita.com/h6akh/items/d241ce878533f6086aa7

- FORTRAN77, C++98/03, Python2

## 若手が今後必要になるプログラミング言語
https://qiita.com/NAKKA-K/items/feb75fcd6ed10979591a

- なんでもいいので好きな言語を学ぼう（好きだとやる気出る→成長できる）
- Ruby, Java, Go, Scala

## 今後必要にならないかもしれないプログラム言語
https://qiita.com/elect/items/72b177a4f1427be4fa31

- Python, Swift, Kotlin, TypeScript, C#, Clojure/ClojureScript, Rust

## その他の記事
すべては取り上げないが、Qiita で検索すると他にもいくらか記事がある。

[「title:"今後必要"」の検索結果 - Qiita](https://qiita.com/search?q=title%3A%22%E4%BB%8A%E5%BE%8C%E5%BF%85%E8%A6%81%22)
Goでテストを書く

### きほん

golangでテストを書く場合は以下のように書く。

```go:main_test.go

package main

import "testing"

func TestHelloWorldを返すか確認するテスト(t *testing.T){
    get := foo()
    if get != "Hello World" {
        t.Errorf("foo() get = %s", get)
    }
}

```
###いろいろなテストパターンを試す

これが一番シンプルな方法だが、いろいろなパターンを試したいときもある。
そのときは以下のように書く。

```go:main_test.go

package cli

import (
	"testing"
)

func Test入力した英語の単語を日本語に変換できることを確認するテスト(t *testing.T) {
    type args struct {
        input string
    }
    tests := []struct {
        name    string
        args    args
        want    string
        wantErr bool
    }{
        {
           name: "ユーザーの入力「hello」を「こんにちは」に変換できることを確認する",
           args: args{
               input: "hello",
           },
           want: "こんにちは",
        },
        {
            name: "ユーザーの入力「world」を「世界」に変換できることを確認する",
            args: args{
                input: "world",
            },
            want: "世界",
        },
        {
            name: "ユーザーの入力「こんにちは」が入力されたときにエラーを返すことを確認する",
            args: args{
                input: "こんにちは",
            },
            want: "",
            wantErr: true,
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            get, err := translate(tt.args.input)
            if wantErr && err == nil {
                t.Errorf("エラーが出力されていません: get = %s err = %v", get, err)
            }
            if !wantErr && get != tt.want) {
                t.Errorf("値が一致していません: get = %v, want = %v", get, tt.want)
            }
        })
    }




```

### 処理をまとめる
処理をまとめたいときはHelperを使う

```go:example.go

package example
 import (
     "testing"
 )
 
 //こっちは出力されない
 func errorf(tb testing.TB, want, got int) {
     tb.Errorf("want = %d, got = %d", want, got)
 }
 
 //tb.Helper()を宣言しないと出力されない
 func errorfHelper(tb testing.TB, want, got int) {
     tb.Helper()
     tb.Errorf("want = %d, got = %d", want, got)
 }

```

### 前後に処理をはさむ

```go:example.go

//テストの前後に処理を挟むにはTestMain(m *testing.M)を使う
 func TestMain(m *testing.M) {
     func() {
         fmt.Println("Prepare test")
     }()
     //m.Run()前後に処理を書くことでm.Run()を中心に処理が実行される。
     ret := m.Run()
     func() {
         fmt.Println("Teardown test")
     }()
     os.Exit(ret)
 }

```

間違いなどがあれば指摘していただければと思います！
Apache spark RDD キャッシュ時の StorageLevel について

##### RDDをキャッシュするメリット
そのRDDに対してアクションを複数回呼ぶ場合、キャッシュから読み込むため、再計算する必要がなくなる。

##### すべてのRDDは常にキャッシュするべきか？ -> いいえ
- 一度しかアクションされないRDDをキャッシュする意味がない
- 複数回アクションされる場合でも、再計算する方が低コストになる場合も

##### キャッシュを持つノードが障害が発生した場合は？
- 再計算される（仮にそのキャッシュが既に不要の場合、無駄な再計算になりそう）
- MEMORY_AND_DISK_2 のように、複数台でキャッシュするようにしておけば、再計算を避けられる

##### StorageLevel 一覧

| StorageLevel | 永続先 | シリアライズ | メリット | デメリット |
|:-----------|:------------|:------------|:------------|:------------|
| NONE | なし | なし | メモリ・ディスク領域消費しない | アクションの毎に再計算 |
| MEMORY_ONLY | メモリ | なし | レイテンシ低い | メモリ消費量多い(GCのオーバーヘッド高) |
| MEMORY_ONLY_SER | メモリ | あり | メモリ消費量少ない | シリアライズのオーバーヘッド(CPU負荷)高　|
| DISK_ONLY | ディスク | なし | メモリ消費しない | レイテンシ高い |
| MEMORY_AND_DISK | メモリとディスク | なし | レイテンシ低い | メモリ消費量多い(GCのオーバーヘッド高) |
| MEMORY_AND_DISK_SER | メモリとディスク | あり | メモリ消費量少ない | シリアライズのオーバーヘッド(CPU負荷)高 |
| OFF_HEAP | Tachyonファイルシステム（メモリ上） | あり | GC発生しない | Tachyon要インストール、実績少ない？ |

##### どの StorageLevel を選択するべきか？
対象のRDDが何度アクションを呼び出されるのか、どのようなアクションなのか、どの程度のサイズになるのか、などに依存する。
とにかく再計算を避けたいのであれば、MEMORY_AND_DISK を選択するのが無難なようにも思えるが、実はトータル的にはパフォーマンスを低下している可能性も考えておく。
Raspberry Piに古いNASをマウント

# 概要
最近VS2017で**.NET Core**の実験を行う機会が増えたので、scpでのファイル移動が面倒になってしまい、Raspberry Piにメーカー名も分からなくなってしまったNASをつなげた。その際の備忘録を時系列で記す。

## Kernel Version
        $ cat /proc/version
        Linux version 4.14.71-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1145 SMP Fri Sep 21 15:38:35 BST 2018

## マウントポイントを作成
        $ sudo mkdir /mnt/nas
        $ sudo chmod 777 /mnt/nas

## マウントしてみる
        $ sudo mount -t cifs //192.168.0.100/share /mnt/nas -o username=UserName,password=Password,rw,uid=1000,gid=1000,iocharset=utf8
        mount error: cifs filesystem not support by the system
        mount error(19): No such device
        Refer to the mount.cifs(8) manual page (e.g. man mount.cifs)

## ググる
        keywords: raspberry pi cifs filesystem not support by the system

[Raspberry Piでcifsが使えなくなった件 - Qiita](https://qiita.com/pochy9n/item/13baabd9294fe505c9e0 ) がHit

        $ cat /proc/filesystems | grep cifs
        $
無反応

        $ sudo rpi-update && reboot
再起動後

        $ cat /proc/filesystems | grep cifs
        nodev   cifs
        $
      
## マウントしてみる２
        $ sudo mount -t cifs //192.168.0.100/share /mnt/nas -o username=UserName,password=Password,rw,uid=1000,gid=1000,iocharset=utf8
        mount error(22): Invalid argument
        Refer to the mount.cifs(8) manual page (e.g. man mount.cifs)

optionについて、綴りを見直したり、入れ替えたり、削ったり、しばし悪戦苦闘...
飽きた。

## ググる２
        Keywords: raspberry pi cifs mount error(22)
**ヒント: 日本語の検索結果のみ表示します。**と表示されているのに日本語ページは9件中1件だけだった。へたれなので日本語のページを見る。
[cifsでmount error(22): Invalid argumentの場合、ver2.1を付ける](https://qiita.com/tukiyo3/items/2b92db3a67edcb729ec1)
とのこと。

## マウントしてみる３
        $ sudo mount -t cifs //192.168.0.100/share /mnt/nas -o username=UserName,password=Password,rw,uid=1000,gid=1000,vers=2.1,iocharset=utf8
        mount error(22): Invalid argument
        Refer to the mount.cifs(8) manual page (e.g. man mount.cifs)
変化なし。
その時、Error出まくりの際logを調べた記憶がよみがえった。

        $ tail -n 10 /var/log/messages
        ...
        Nov  9 23:07:28 raspberrypi kernel: [  281.907124] FS-Cache: Netfs 'cifs' registered for caching
        Nov  9 23:07:28 raspberrypi kernel: [  281.909328] Key type cifs.spnego registered
        Nov  9 23:07:28 raspberrypi kernel: [  281.909349] Key type cifs.idmap registered
        Nov  9 23:07:28 raspberrypi kernel: [  281.910584] No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3 (or SMB2.1) specify vers=1.0 on mount.

最後の行にvers=1.0にしろと書かれていた。NASが古くてSMB1しか解さないのが原因だった。
同様のメッセージが /var/log/kern.log にも吐かれていた。
Invalid argumentって出るから、綴り間違いだと勘違いしてしまっていた。

## マウントする
        $ sudo mount -t cifs //192.168.0.100/share /mnt/nas -o username=UserName,password=Password,rw,uid=1000,gid=1000,vers=1.0,iocharset=utf8
        $
       
# 結論
新しいNASの箱が欲しい。
SMB1にはセキュリティに対する脆弱性が見つかっているので、皆さんはマネしないこと。
Phoenix 1.4正式版① インストール編

[fukuoka.ex](https://fukuokaex.connpass.com/)代表のpiacereです
ご覧いただいて、ありがとうございます:bow:

ElixirのWebフレームワーク「Phoenix」の新バージョンである1.4が、rcが取れ、正式リリースされました:stuck_out_tongue_closed_eyes:

https://phoenixframework.org/blog/phoenix-1-4-0-released
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/cebb2d97-9c9c-ba8d-dfd4-5f81b0da6f67.png)

インストールして、試してみましょう

参考までに、rc版を試したときのコラムは、以下になります
　|> [<b>Phoenix 1.4rcを試す① アップデート紹介編</b>](https://qiita.com/piacere_ex/items/34a56a418a99701a0ac1)
　|> [<b>Phoenix 1.4rcを試す② インストール編（不具合時の復旧もあるよ）</b>](https://qiita.com/piacere_ex/items/f4fb3fecb359e798ef01)
　|> [<b>Phoenix 1.4rcを試す③ ローカルSSL開発編（Gigalixirのオマケ付）</b>](https://qiita.com/piacere_ex/items/28f2f655241d142980d8)
　|> [<b>Phoenix 1.4rcを試す④ webpack編</b>](https://qiita.com/piacere_ex/items/86c133c4ed97504ab991)

内容が、面白かったり、気に入ったら、「いいね」よろしくお願いします :wink:

# 既存Phoenixのアンインストール

既にPhoenix 1.3系や1.4.0-rc系がインストールされている場合は、まずアンインストールが必要です

Phoenix 1.3系は、以下でアンインストールします

```
mix archive.uninstall phx_new
```

Phoenix 1.4.0-rc系は、以下でアンインストールします（「rc-」の後ろには、インストール中のバージョンが入ります）

```
mix archive.uninstall phx_new-1.4.0-rc.1
```

どのバージョンを入れているか不明のときは、以下コマンドで確認できます

```
mix archive
```

# Phoenix 1.4.0のインストール

以下でPhoenix 1.4.0がインストールできます

```
mix archive.install hex phx_new 1.4.0
```

# Phoenix 1.4.0のPJ作成、動作確認

インストール後、以下手順で、Phoenix PJを作成してください

なお、PJ名に「Web」という文字列を含むと、フォルダ作成やモジュール命名の都合から、不具合が出るため、入れないよう気を付けてください（エラーメッセージから判断付けるのは、かなり困難なので、ご注意を）

```
mix phx.new phx14_sample --no-webpack --no-ecto
　…（ファイル作成ログが続く）…
Fetch and install dependencies? [Yn] （←y、Enterを入力）
cd phx14_sample
iex -S mix phx.server
```

Phoenix起動の際、以下ログが出ていれば起動成功です

```
…
[info] Running BlogWeb.Endpoint with cowboy 2.5.0 at http://localhost:4000
Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help)
iex> 
```

rc版からの変更点として、Cowboyのデフォルトバージョンが、1系では無く、2系である2.5に変わっていましたので、自前でmix.exsのdepsを変更して、Cowboy 2系に切り替える必要が無くなりました

そういえば、rc時に発生していた、cowbloy_plugが無くてエラーが出る現象が、解消されていました…はぁ、良かったこれでまともに使える:relieved:

待望のLiveViewは、今回は残念ながら含まれませんでしたが、Telemetryは入っているっぽいです

さて、ブラウザで「```http://localhost:4000```」をアクセスすると、以下ページが表示されます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/6f0e6970-5536-2af3-3bb9-50b07bf26ba3.png)

# 終わり

今回は、Phoenix 1.4.0のインストールを行いました

[次回は、Phoenix 1.4.0を使って、DB+APIを作ってみよう](https://qiita.com/piacere_ex/items/b63417540378ab9cbd18)と思います

# p.s.「いいね」よろしくお願いします

よろしければ、ページ左上の ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/4d515047-cc48-382e-c2b1-3ad0cc50dbbf.png) や ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/a4e3da58-70a3-4197-95a2-6a6906650d01.png) のクリックをお願いしますー:bow:
Ruby で Slack 通知サンプル

いつも忘れるのでメモしておきます。

```ruby:script.rb
require "net/http"
require "json"
puts "start script.rb 🌝"
SLACK_URL = "https://hooks.slack.com/services/***/***"

def talk_to_slack
  params = {
    text: "ruby",
  }
  notify_to_slack(params)
end

def notify_to_slack(params)
  uri = URI.parse(SLACK_URL)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.start do
    request = Net::HTTP::Post.new(uri.path)
    request.set_form_data(payload: params.to_json)
    http.request(request)
  end
end

talk_to_slack
```
タグの語源表

<tbody>
<tr>
<th>nav</th>
<td>navigation links</td>
</tr>
<tr>
<th>h*</th>
<td>heading *</td>
</tr>
<tr>
<th>hgroup</th>
<td>heading group</td>
</tr>
<tr>
<th>p</th>
<td>paragraph</td>
</tr>
<tr>
<th>hr</th>
<td>horizontal rule</td>
</tr>
<tr>
<th>pre</th>
<td>preformatted text</td>
</tr>
<tr>
<th>ol</th>
<td>ordered list</td>
</tr>
<tr>
<th>ul</th>
<td>unordered list</td>
</tr>
<tr>
<th>li</th>
<td>list item</td>
</tr>
<tr>
<th>dl</th>
<td>description list</td>
</tr>
<tr>
<th>dt</th>
<td>description term</td>
</tr>
<tr>
<th>dd</th>
<td>description description</td>
</tr>
<tr>
<th>figcaption</th>
<td>figure caption</td>
</tr>
<tr>
<th>div</th>
<td>division</td>
</tr>
<tr>
<th>a</th>
<td>anchor</td>
</tr>
<tr>
<th>em</th>
<td>emphasis</td>
</tr>
<tr>
<th>s</th>
<td>strike</td>
</tr>
<tr>
<th>q</th>
<td>quotation</td>
</tr>
<tr>
<th>dfn</th>
<td>definition</td>
</tr>
<tr>
<th>abbr</th>
<td>abbreviation</td>
</tr>
<tr>
<th>var</th>
<td>variable</td>
</tr>
<tr>
<th>samp</th>
<td>sample</td>
</tr>
<tr>
<th>kbd</th>
<td>keyboard</td>
</tr>
<tr>
<th>sub</th>
<td>subscript</td>
</tr>
<tr>
<th>sup</th>
<td>superscript</td>
</tr>
<tr>
<th>i</th>
<td>italic</td>
</tr>
<tr>
<th>b</th>
<td>bold</td>
</tr>
<tr>
<th>u</th>
<td>underline</td>
</tr>
<tr>
<th>rt</th>
<td>ruby text</td>
</tr>
<tr>
<th>rp</th>
<td>ruby parentheses</td>
</tr>
<tr>
<th>bdi</th>
<td>bi-directional isoration</td>
</tr>
<tr>
<th>bdo</th>
<td>bi-directional override</td>
</tr>
<tr>
<th>br</th>
<td>break</td>
</tr>
<tr>
<th>wbr</th>
<td>word break</td>
</tr>
<tr>
<th>ins</th>
<td>insert</td>
</tr>
<tr>
<th>del</th>
<td>delete</td>
</tr>
<tr>
<th>img</th>
<td>image</td>
</tr>
<tr>
<th>iframe</th>
<td>inline frame</td>
</tr>
<tr>
<th>param</th>
<td>parameter</td>
</tr>
<tr>
<th>colgroup</th>
<td>column group</td>
</tr>
<tr>
<th>col</th>
<td>column</td>
</tr>
<tr>
<th>tbody</th>
<td>table body</td>
</tr>
<tr>
<th>thead</th>
<td>table header</td>
</tr>
<tr>
<th>tfoot</th>
<td>table footer</td>
</tr>
<tr>
<th>tr</th>
<td>table row</td>
</tr>
<tr>
<th>td</th>
<td>table data cell</td>
</tr>
<tr>
<th>th</th>
<td>table header cell</td>
</tr>
<tr>
<th>optgroup</th>
<td>option group</td>
</tr>
<tr>
<th>keygen</th>
<td>key-pair generator</td>
</tr>
</tbody>
PHP から Chatwork にメッセージを送信

# PHP から Chatwork にメッセージを送信

まずは動かしてみる Hello world 的なサンプル。

## Step1.

~~~bash
composer require kitchenu/chatwork-php
~~~

## Step2.
ここから Chatwork の API Token を発行してきます。
https://www.chatwork.com/service/packages/chatwork/subpackages/api/token.php


## Step3.

送信先 RoomID は 送信したい chatwork のルームのURLを確認します。
もし、URL が `https://www.chatwork.com/#!rid1234xxxx` だったら `1234xxxx` の部分が RoomID です。

~~~php
<?php
	require_once "vendor/autoload.php";
 
	$token = "591aaec4xxxxxxxxxxxxxxxxxxxxxxxx";		// chatwork api token
	$options = [		// 内部で使われてる GuzzleHttp Client に渡す オプション
		'verify' => false,		// false にすると SSL証明書確認しない。通常は true が望ましい。
	];
	$chatwork = new \Kitchenu\Chatwork\Client($token, $options);

	$room = "1234xxxx";
	$message = "Hello world.";
	$unread = 1;	// 0:既読 1:未読
	$chatwork->postRoomMessages([
		'room_id' => $room,
		'body' => $message,
		'self_unread' => $unread
	]);

	// 送信完了

~~~

以上で送信完了


--------

- Composer に `wataridori/chatwork-sdk` や  `polidog/php-chatwork-api` もあったが、中身のソースコードも確認した結果、  `kitchenu/chatwork-php` というパッケージがシンプルで使いやすいと思います。
- Exception `SSL certificate problem: unable to get local issuer certificate` が出る場合 	`$options = [ 'verify' => false ]` で一時的に回避
Chromeショートカットキーまとめ

# 概要
家では長らくWindowsを使ってきたが、最近から職場でMacを使うようになったので
個人的に必要なChromeショートカットキーを一覧化しておく。

# 前提
- OS
  - 家　：WIndows10 Pro
  - 職場：Mac OS Mojave
- Macのキーの読み替え対応
  - ⌘：command
  - ⇧：shift
  - ⌥：option
  - ⌃：control

# ショートカットキー
個人的重要度高いやつから順番にあげていく。

|やりたいこと					|Winキー操作		|Macキー操作		|備考|
|-----------------------------------------------|-----------------------|-----------------------|----|
|開発者ツールを開く				|F12			|⌘ + ⌥ + i		|    |
|新しいタブを開く				|Ctrl + T		|⌘ + n			|    |
|タブを閉じる					|Ctrl + W		|⌘ + ⇧ + w		|    |
|閉じたタブを再度開く				|Ctrl + Shift + T	|⌘ + ⇧ + t		|    |
|ひとつ右のタブを選択する				|Ctrl + Tab		|⌘ + ⌥ + →		|    |
|ひとつ左のタブを選択する				|Ctrl + Shift + Tab	|⌘ + ⌥ + ←		|    |
|指定したタブを選択する				|Ctrl + 1 ~ 8		|⌘ + 1 ~ 8		|一番左から数えて何番目のタブか指定|
|最後のタブを選択する				|Ctrl + 9		|⌘ + 9			|    |
|アドレスバーにフォーカス				|Ctrl + L		|⌘ + l			|    |
|現在のタブでGoogle検索する			|Ctrl + K		|⌘ + ⌥ + f		|    |
|新しいタブでGoogle検索する			|入力+Alt+Enter		|該当なし		|    |
|サイト名に www. と .com を追加して現在のタブで開く|入力 + Ctrl + Enter	|入力 + ⌃ + enter　　	|アドレスバー入力|
|サイト名に www. と .com を追加して新しいタブで開く|該当なし		|入力 + ⌃ + ⇧ + enter	|アドレスバー入力|
|閲覧履歴データを消去する				|Ctrl + Shift + Delete	|⌘ + ⇧ + delete	|    |
|閲覧履歴ページを表示する				|Ctrl + H		|⌘ + y			|    |
|ウェブページを 1 画面ずつ下にスクロールする	|Space または PgDn	|space			|    |
|ウェブページを 1 画面ずつ上にスクロールする	|Shift+Space または PgUp	|⇧ + space		|    |
|ページ内検索					|Ctrl + F		|⌘ + f			|    |
|ページの先頭に移動する				|Home			|⌘ + ↑			|    |
|ページの最後に移動する				|End			|⌘ + ↓			|    |
|テキスト欄内で前にある単語の先頭にカーソルを移動する|Ctrl + 左矢印		|⌥ + ←			|テキスト編集中のおはなし|
|テキスト欄内で次にある単語の後ろにカーソルを移動する|Ctrl + 右矢印		|⌥ + →			|テキスト編集中のおはなし|
|テキスト欄内で前にある単語を削除する		|Ctrl + Backspace	|⌥ + delete		|テキスト編集中のおはなし|
|新しいウィンドウを開く				|Ctrl + N		|⌘ + n			|    |
|パソコンのファイルを Chrome で開く		|Ctrl + O +ファイルを選択|⌘ + o + ファイルを選択	|    |
|HTMLソースを表示				|Ctrl + U		|⌘ + ⌥ + u		|    |
|ブックマークに追加				|Ctrl + D		|⌘ + d			|    |
|リンク先をダウンロードする			|Alt + リンクをクリック	|⌥ + リンクをクリック	|    |
|ダウンロードページを開く				|Ctrl + J		|⌘ + ⇧ + j		|    |
|ホームページを現在のタブで開く			|Alt + Home		|⌘ + shift + h		|    |
|Chrome メニューを開く				|Alt + F		|⌘ + ,			|    |

# 参考
- [Chrome のキーボード ショートカット](https://support.google.com/chrome/answer/157179?hl=ja)
React v16で実装された new Context APIを使って、Reduxへ別れを告げる②

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

context APIはreactだけで、global stateを実現するためのAPIです。
以下の記事にcontext apiの概要が載っています。
[React v16で実装された new Context APIを使って、Reduxへ別れを告げる](https://qiita.com/loverails/items/50126e874b24ff984471)
基本的に、unstated　という、contextAPIを超薄く拡張したライブラリがあるので、実務では生のContextAPIを使うのではなく、unstatedを使うことをオススメしています。

# Context APIは神からの祝福です！

学習コストと言うものが存在せず、コード量も少ないので、プロトタイプ製作にとても適しています。
実戦で使っている記事を見ないので、どの様にContext Apiで設計をするのかを記事にしてみました。

それではどの様に実戦的にcontext apiを使うか見てみましょう。
Fluxデザインパターンに従い、reduxから如何に簡単に移行するかに重点を置いて設計します。
まず、componentにどの様にstoreの中のstateが渡されるか見てみましょう。

Context APiを使いProviderとConnectという自作クラスを作り、それによってglobal stateを管理します。

###Proveiderは、 storeをcomponentに渡すための自作クラスです。
Routesはここではアプリのroot componentです。

```Provider.js
import React from 'react'
import Routes from './Routes'
import {Provider} from './Redux'

const App = () =>
  <Provider>
    <Routes />
  </Provider>

export default App
```

### Connectはcomponentにstoreを接続するための自作クラスです。

```Home.js
import React, { Component } from 'react'
import { Text, View } from 'react-native'
import { Connect } from '../Redux'

class Home extends Component {
   render() {
    const {age, increment} = this.props.store
    return (
      <View>
        <Text>{age}</Text>
        <Text onPress={() => increment()}>Increment!</Text>
      </View>
    )
  }
}

export default Connect(Home)
```

それでは、以上の二つの関数を自作していきましょう。

## Context APIで Reduxを再現
まず、Context Apiを使うために、Storeと、Provider, connectを作ります。
クラスのstateを、Storeとして扱い、reducerの代わりにsetStateを使います。

```Redux.js
import React from 'react'

const Store = React.createContext()

export class Provider extends React.Component {
  /*--- store ---*/
  state = {
    age: 0
  }

  /*--- reducers ---*/
  increment = () => this.setState({age: this.state.age + 1})

  /*--- combineReducer ---*/
  render () {
    return (
      <Store.Provider
        value={{
          ...this.state,
          increment: this.increment
        }}
      >
        {this.props.children}
      </Store.Provider>
    )
  }
}

/*--- connect ---*/
export const Connect = ChildComponent => props =>
  <Store.Consumer>
    {context => <ChildComponent {...props} store={context}  />}
  </Store.Consumer>
```


## Reduxとの比較
超お手軽で、学習コストが低いですね。小規模アプリにはこれ以上ないほどの選択肢ですね。
10ページぐらいのアプリなら問題なく動きます。reduxの1/3のコード量です。
もう私はcontext　APIなしでは個人開発ができなくなりました。

ただし、アプリが肥大化していくと、独自ルールが辛くなってきます。拡張性もありません。非同期もrxjsを使っても書きづらいです。
しかし問題ありません。我々にはreduxがいます。
context APIなんてゴミは捨て、reduxへと移行すればいいのです。巨大なエコシステムと堅牢性が我々を幸せにしてくれます。
Redux 万歳！！！
さくらレンタルサーバでUTF8のmecabの辞書を使う方法

さくらのレンタルサーバではデフォルトでmecabは入っているものの
使える文字コードがEUC-JPなためコマンドからだと以下のような結果となってしまいます。

```
% mecab
すもももももももものうち
すもももももももものうち	????,????,*,*,*,*,*
```

任意で辞書を入れてUTF-8を扱えるようにします。

辞書ファイルをここからダウンロードして解凍からmakeまで
http://taku910.github.io/mecab/

```
% tar xvzf mecab-ipadic-2.7.0-20070801.tar.gz
% cd mecab-ipadic-2.7.0-20070801
% ./configure --prefix=$HOME/usr/local --with-charset=utf8
% make
```

続いてインストールしようとすると以下のようなエラーが出ます。

```
% make install
/bin/sh ./mkinstalldirs /usr/local/lib/mecab/dic/ipadic
 /usr/bin/install -c -m 644 ./matrix.bin /usr/local/lib/mecab/dic/ipadic/matrix.bin
install: /usr/local/lib/mecab/dic/ipadic/matrix.bin: Permission denied
```

要するに権限ないところにどうこうしようとしているということです。
Makefileを編集して回避

```
MECAB_DICDIR = /usr/local/lib/mecab/dic/ipadic
dicdir = /usr/local/lib/mecab/dic/ipadic
```
以上の２行を以下のように変更

```
MECAB_DICDIR = /home/ユーザー名/usr/local/lib/mecab/dic/ipadic
dicdir = /home/ユーザー名/usr/local/lib/mecab/dic/ipadic
```

編集が終わったらインストール開始

```
make install
```
これで成功するはず

では早速検証

```
% mecab -d /home/ユーザー名/usr/local/lib/mecab/dic/ipadic
すもももももももものうち
すもも	名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
の	助詞,連体化,*,*,*,*,の,ノ,ノ
うち	名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
```

成功しました。
circle-ciでversion2.1を使ってみる

## tl;dr
version2.1だと結構便利な機能がいろいろ追加されているようなので使ってみる。

- executors
- commands
- workflows (version 2.0)

## とにかく書いてみる
```yml:.circleci/config.yml
version: 2.1

executors:
  default:
    working_directory: ~/repo
    docker:
      - image: circleci/php:7

commands:
  composer_install_with_cache:
    steps:
      - restore_cache:
          keys:
            - v1-composer-deps-{{ checksum "composer.json" }}
            - v1-composer-deps-
      - run: composer install -n --prefer-dist
      - save_cache:
          key: v1-composer-deps-{{ checksum "composer.json" }}
          paths:
            - ./vendor

jobs:
  checkout_code:
    executor: default
    steps:
      - checkout
      - composer_install_with_cache
      - save_cache: # ソースコードをキャッシュ
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
          paths:
            - ~/repo

  test:
    executor: default
    steps:
      - restore_cache: # ソースコードの復元
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}

      - run: phpunit

workflows:
  version: 2
  build:
    jobs:
      - checkout_code
      - test:
          requires: # checkout_codeの後に実行する
            - checkout_code
```

## 設定ファイルチェック
記述が間違っていないかチェックする。

```bash:ターミナル
$ circleci config validate
Config file at .circleci/config.yml is valid.
```

## 実行結果
Workflowを使ったことで下記のようにジョブが２つ実行されました。
![job.png](https://qiita-image-store.s3.amazonaws.com/0/142279/79536bde-1d24-6ee7-4753-c139bdaa5db7.png)

version2.1になると各処理をスッキリ書けていい感じですね。

## ローカル実行について
ローカル実行しようとすると対応していないとエラーになるのが残念。

```bash:ターミナル
$ circleci local execute
Error: 
You attempted to run a local build with version '2.1' of configuration.
Local builds do not support that version at this time.
You can use 'circleci config process' to pre-process your config into a version that local builds can run (see 'circleci help config process' for more information)
```

ただし、下記のコマンドで2.0に変換すれば実行可能なようです。

```bash:ターミナル
# 設定ファイルの変換 (2.1 -> 2.0)
$ circleci config process .circleci/config.yml > process.yml

# チェックアウトのジョブを実行
$ circleci local execute -c process.yml --job checkout-code
　　・
　　・
　　・
====>> echo "compoer install."
  #!/bin/bash -eo pipefail
compoer install -n --prefer-dist
====>> Saving Cache
Error: 
Skipping cache - error checking storage: not supported

Step failed
Success!

# テストのジョブを実行
$ circleci local execute -c process.yml --job test
```

キャッシュでエラーが出たり、ジョブを個別に実行するなど、ひと手間かかったりとちょっと面倒ではありますね。

## 参考サイト・資料
* [WEB＋DB PRESS vol.107 実践CircleCI](https://gihyo.jp/magazine/wdpress/archive/2018/vol107)
* [https://www.kaizenprogrammer.com/entry/2018/10/01/035657](CircleCI 2.1 の新機能で yaml の記述を DRY にする方法)
LaTeXコマンド集

LaTeXのコマンドをまとめておきます．
間違いなどありましたらコメントしていただければ順次訂正していきます．
# ギリシャ文字

|大文字|コマンド|小文字|コマンド|読み方|
|:-------------|:--------------|:--------------|:------------|:----------|
| $A$ | A | $\alpha$ | \alpha | アルファ |
| $B$ | B | $\beta$ |\beta            |ベータ|
|$\Gamma$      |\Gamma             |$\gamma$           |\gamma           |ガンマ|
|$\Delta$          |\Delta             |$\delta$           | \delta          |デルタ |
|$E$  | E  |$\epsilon$   | \epsilon  | イプシロン，エプシロン |
|$Z$  | Z  |$\zeta$  | \zeta  | ゼータ |
|$H$   | H  | $\eta$  | \eta  | イータ，エータ |
|$\Theta$   | \Theta  | $\theta$  | \theta  | シータ，テータ，セータ |
|$I$   | I  |$\iota$   | \iota  | イオタ |
|$K$   | K  |$\kappa$  | \kappa  | カッパ |
|$\Lambda$   | \Lambda  |$\lambda$   | \lambda  | ラムダ |
| $M$  | M  | $\mu$  | \mu  | ミュー |
| $N$  | N  | $\nu$  | \nu  | ニュー |
| $\Xi$  | \Xi  | $\xi$  | \xi  | クシー，クサイ，グザイ |
| $O$  | O  | $o$  | o  | オミクロン |
| $\Pi$  | \Pi  | $\pi$  | \pi  | パイ |
| $P$  | P  | $\rho$  | \rho  | ロー |
| $\Sigma$  | \Sigma  | $\sigma$  | \sigma  | シグマ |
| $T$  | T  | $\tau$  | \tau  | タウ |
| $\Upsilon$  | \Upsilon  | $\upsilon$  | \upsilon  | ユプシロン，ウプシロン |
| $\Phi$  | \Phi  | $\phi$  | \phi  | ファイ |
| $X$  | X  | $\chi$  | \chi  | カイ，キー |
| $\Psi$  | \Psi  | $\psi$  | \psi  | プシー，プサイ |
| $\Omega$  | \Omega  | $\omega$  | \omega  | オメガ |



#アクセント
| アクセント  | コマンド  |
|:--|:--|
| $\hat{x}$  | \hat{x}  |
| $\check{x}$  | \check{x} |
| $\breve{x}$  | \breve{x}  |
| $\acute{x}$  | \acute{x} |
| $\grave{x}$  | \grave{x}  |
| $\tilde{x}$  | \tilde{x} |
| $\bar{x}$  | \bar{x}  |
| $\vec{x}$  | \vec{x} |
| $\dot{x}$  | \dot{x}  |
| $\ddot{x}$  | \ddot{x} |
homebrewでVirtualBoxとVagrantインストール(初心者向け、Mac)

# 趣旨
VirtualBoxとVagrantを利用してLinux環境構築をしたいときに
せっかくならhomebrew使ってやりたい！
ということで、やってみました。
自分の備忘録として、初心者向けの記事として、丁寧に記録を残したいと思います。
# 環境
homebrewはインストール済みの状態
# homebrew
macOS向けのパッケージマネージャー
# brew-cask
homebrewの拡張機能
MacのGUIアプリケーションもコマンド一発で管理できるように
# virtualboxのダウンロード
```
$ brew search virtualbox
2018-11-10 12:17:02.595 defaults[32749:1604438] 
The domain/default pair of (kCFPreferencesAnyApplication, AppleLanguages) does not exist
==> Casks
virtualbox
virtualbox-extension-pack
homebrew/cask-versions/virtualbox-beta
homebrew/cask-versions/virtualbox-extension-pack-beta
AkienoMacBook-Pro:~ akie$ brew install virtualbox
```
VirtualBoxがhomebrew-caskでインストールできることが確認できました

```
$ brew cask install virtualbox
==> Satisfying dependencies
==> Downloading https://download.virtualbox.org/virtualbox/5.2.20/VirtualBox-5.2.20-125813-OSX.dmg
######################################################################## 100.0%
==> Verifying SHA-256 checksum for Cask 'virtualbox'.
==> Installing Cask virtualbox
==> Running installer for virtualbox; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are ignored.
Password:
installer: Package name is Oracle VM VirtualBox
installer: Installing at base path /
installer: The install was successful.
🍺  virtualbox was successfully installed!
```
インストールできました

# 確認
```
$ brew cask list
virtualbox
```
一覧にVirtual Boxが表示されました

# Vagrantのインストール
VirtualBoxの操作を簡単にしてくれます

```
$ brew search vagrant
2018-11-10 12:37:31.730 defaults[34303:1623081] 
The domain/default pair of (kCFPreferencesAnyApplication, AppleLanguages) does not exist
==> Formulae
vagrant-completion

==> Casks
vagrant                             vagrant-manager                     vagrant-vmware-utility
$ brew cask install vagrant
==> Satisfying dependencies
==> Downloading https://releases.hashicorp.com/vagrant/2.2.0/vagrant_2.2.0_x86_64.dmg
######################################################################## 100.0%
==> Verifying SHA-256 checksum for Cask 'vagrant'.
==> Installing Cask vagrant
==> Running installer for vagrant; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are ignored.
Password:
installer: Package name is Vagrant
installer: Upgrading at base path /
installer: The upgrade was successful.
🍺  vagrant was successfully installed!
$ brew cask list
vagrant                             virtualbox
```
インストールされました

# まとめ
コマンドだけでGUIアプリも管理できて、便利です！
VirtualBoxを使って、開発・勉強を進めていきたいと思います

# TODO
```
The domain/default pair of (kCFPreferencesAnyApplication, AppleLanguages) does not exist
```
が出てくるのがよくわからないです。一旦保留。
Raspberry PiへSSH接続

# SSH接続
Raspberry PiへのWindows10で実行しているWindows Subsystem for linuxからRaspberry PiにSSH接続します。WSLではUbuntuを使用しています。また、WSL自体のインストールは参考資料のURLを参照して下さい。WSLは入っている前提で進めます。環境は以下に示します。

| ソフトもしくはハード        |       バージョン | 
|:-----------------:|:------------------:|
| Raspberry pi         |              Model 3 b+ |  
| WSL           |            Ubuntu 16.04.5 LTS |  
| Python             |              2.7 |    

## サーバ側(Raspberry Pi)
以下のコマンドでRaspberry piのIPアドレスを確認します。

```bash

$ ifconfig
```

ここで、Raspberry PiのIPアドレスを確認します。確認するIPアドレスはPC(Windows10)と同一のネットワーク通信方式のものです。同じWifiで接続されている場合には、wifi0と言った記載があります。その項目のinet adderのIPアドレスをコピーします。以下に例を示します。

![図1.png](https://qiita-image-store.s3.amazonaws.com/0/169342/c2f32d29-2ba3-88b2-d8a4-b99a02266d8e.png)

## クライアント側(WSL)
以下のコマンドでRaspberry PiにSSH接続します。

```bash

$ ssh pi@"確認したIPアドレス"
```


# ssh出来なかった時

ssh接続できなかった場合には、Raspberry PiのSSH設定が有効になっていないことが考えられるので、コマンドウィンドウで以下のコマンドを実行し、SSHの設定を変更してください。

```bash

$ sudo raspi-config
```

Interfacing Option > SSH > enable

# 参考
https://qiita.com/Aruneko/items/c79810b0b015bebf30bb
JJUG CCC Spring2018メモ

投稿してなかった...


まだまだこれから！JUnit5入門/進藤　遼さん
===========
 - JUnit5
    - Junit4の後継バージョン
    - 2017年9月　GA
    - JDK baseline 8+ 
 
 - テストフレームワークに求めるもの(大事な要素)
    - 簡潔さ・可読性
    - 一貫性
    - 拡張性
 - Junit5の良くなったところ
    - 大事な要素が良くなっている
 - Junit5 demerit
    - 1.8+
    - パッケージが異なる
    - 大きく変わった構造化テスト・パラメータ化テスト
    - FW,IDE対応がまちまち


セットアップ(違うところ)
----------
-     - マルチモジュール構成(Junit5の構成は3つ！)
        - junit platform (テスト実行基盤)
            - luncher, IDE上で動かない
        - junit jupitaer(新テストAPI)
            - @Testとか
        - junit vintage
            - マイグレーションサポート

Junit5.2 → Bill of Materials
 - ↑のモジュールバージョンの組み合わせをうまく提供してくれる

テストの書き方で変わったところ
---------

### プチ変わった
- @test 
    - 4 public only
    - 5 非publicクラス/メソッドもOK
- 4 @BeforeClass/@before?
- 5 @BeforeAll/@BeforeEach
    - before /after の区別なしでよい
- @ignore -> @Disabled

- テストメソッド名
    - 4 テスト名　＝テストメソッド名
    - 5 @DisplayName

### 結構変わった(嬉しい新機能)
 - アサーション
    - assertEquals
        - 引数の順序変わる
    - アサーショングループ化
        - 4 一つのテスト(@Test)のなかに複数アサーションがあるとき、一つ間違えたら後続が実行されない
        - 5 実行される！
            - assertAll() ラムダ式で複数かける！すべてのアサートしてすべてOKならOKを返す
    - 例外の検証
        - 4 @Test(expected = ...Exception.class) or try-catch
        - ５ assertThrows(<投げられたい例外クラス>, ラムダ式で発生するだろう処理を記載)


構造化テスト・パラメータ化テスト
----
 - 構造化テスト
    - 4 public static class -> テストのためのインナークラス(グループ)
    - 5 インナークラスとテストメソッドが共存できる using `@Nested`

 - パラメータ化テスト
    - 4 `@Runwith(Theories.class ... テストランナー)` `@DAtaPoints` `@Theory`
    - 5 junit-jupiter-param module / 
    - ...そもそも パラメータ化テスト テストメソッドの引数にパラメータをいれて自動で回す機能


拡張モデル
----
 - テストクラスの拡張方法
    - 4 Runnner (@Runwith), Rule
    - 5 @ExtendsWith, 複数指定可


マイグレーション
-----
 1. 書き換える
    - assertEqualsの引数変更...
    - Rule,RunnerはExtensionに書き換え
 2. マイグレーションモジュール(Junit vintage使用)
Apache IgniteのUIを提供するApache Ignite Extensionsを使ってみる

# はじめに

Apache Igniteは、インメモリデータグリッドを実現するミドルウェアです。インメモリデータグリッドとは、大量のデータを複数のサーバ上のメモリで分散化する技術です。

今回使ってみたApache Ignite ExtensionsはIgniteと接続し、トポロジーやキャッシュの操作を行うUIを提供するソフトウェアです。

Apache Igniteの公式ページでも以下のように紹介されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/78f11913-0875-0312-0752-e3f130b91d41.png)
https://ignite.apache.org/addons.html#web-console

Apache Ignite ExtensionsのREADMEを参考にインストールしてみます。

https://github.com/sumeet70/aiex/blob/master/README.md


# 前提条件

- CentOS 7.5を使用します。
- Apache Igniteはインストール済みです。
- gitがインストール済みです。


# Apache Ignite Extensionsをインストールする

## Node.jsのインストール

```
# curl -sL https://rpm.nodesource.com/setup_6.x | bash -
# yum install -y nodejs
# node -v
v6.14.4
```

## リポジトリのコピーを取得

```
# git clone https://github.com/sumeet70/aiex.git
```

## Apache Ignite Extensionsのインストールと起動

```
# npm install bower -g 
# cd aiex
# npm install
# bower install --allow-root
→ rootで実行していたので「--allow-root」が必要。お試し環境以外ではrootでインストールするのはやめましょう。
# export IGNITE_REST=localhost:8080 
# npm start
```

## ブラウザで表示する。

以下のアドレスでApache Ignite ExtensionsのUIにアクセスできます。

http://[IPアドレス]:8081/

以下のようにノードの情報が表示できる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/97caa980-1c4f-7d1f-3dc3-8408172b429d.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/52e07380-84c2-e090-2859-6b8520459376.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/d12172cb-03e1-4abd-2c34-fe45efed4362.png)


キャッシュの操作もできる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/773c9900-5219-be39-1439-5940785071cb.png)


# 最後に

Apache Ignite Extensionsのインストールは簡単でした。
しかし、使ってみるとキャッシュの操作はあまり使いやすくはなく、トポロジーも頻繁に確認したいものではないので、あまり便利ではないかなという印象です。
また、ログのタブもあるのですが、現時点では未実装です。
よくよく見るとGitHubを見ると最近は更新もされていないようです。

プロダクション環境であれば、GridGain社の「GridGain Web Console」も選択肢になるかな。（使ったことありませんが）
JavaScriptのシグネチャの読み方

## 前置き
axiosというHTTPクライアントのREADMEを読んでいると、以下のようなシグネチャがでてきた。
どう読むんだろう、、🤔

```javascript
axios#post(url[, data[, config]])
```

axiosのGitHub
https://github.com/axios/axios


断っておくとこの書き方はaxiosだけに出てくるものではなく、
MDNのようなサイトでもこのような記法が随所にでてくる。

MDNのforEach()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

というわけで調べた。

## 結論
結論、`[]`の部分は任意ということになる。

axiosの例であれば、以下のような書き方は問題ない。

```javascript
axios#post(url)

axios#post(url, data)

axios#post(url, data, config)
```

反対に以下のようなdataを飛ばして、その先のconfigを指定するといった書き方はできない。

```javascript
axios#post(url, config)
```

## 参照
https://teratail.com/questions/157266
Qiitaを名刺にしよう。システムエンジニアのキャリア術・就職対策。「本名刻印メソッド」のススメ。

# Qiitaの「プロフィールページ」に実名はない

名刺代わりにできない。

基本的にはGoogleに強いサービスなのに残念すぎる。

なのでこんな風に、自己紹介「がわり」になる記事には、自分の実名を入れてあげる。

[瞑想するエンジニア ( by 稲浦悠馬 Yuma Inaura ) — Googleやスティーブ・ジョブズに学ぶ「マインドフルネス」のススメ— - Qiita](https://qiita.com/YumaInaura/items/f1a55b0b342954224207)

# Google検索で自分の名前を検索すると「名刺記事」のほうが上に来る

プロフィールページよりも「本名刻印メソッド」を実行した記事のほうが強そう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/3c934349-b5c8-e98a-9628-53c00546791a.png)

2018-11-10 現在

# 「キャッチフレーズ」で検索してもらうことも出来る


![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/47a362f7-5e42-9847-ec94-1b15da1a5bbc.png)

# まとめ

刻印しようぜ。

# あわせて読みたい？

- [「自分ブランド」を確立するセルフブランディング術。実名で全てのソーシャルアカウントを統一してキャリアアップ・就職・転職対策してみよう。 by 稲浦悠馬 YumaInaura - Qiita](https://qiita.com/YumaInaura/items/76ce5f63a47e44f0193b)
- [Qiitaを名刺代わりにしたい—本名でGoogle検索した時にプロフィールページが出てきてほしい - Qiita](https://qiita.com/YumaInaura/items/d36130d9f353dfdfe91d)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->