OmniAICreator/Qiita-1.07M huggingface dataset:
ChefTips: SALT付きSHA-512でパスワードのshadow hashを生成する



## 解決したい課題
Chefでは、`user`リソースの`password`プロパティにハッシュ化されたパスワードを記述することで、ユーザのパスワードを設定することができます。世の中のChefハウツー記事とかをみていると、パスワードをハッシュ化する方法として以下の `MD5` でのハッシュを紹介している例が多いようです。

`openssl passwd -1 "theplaintextpassword"`

> Chef社公式でも実際に紹介されていますし…
> [https://docs.chef.io/resource_user.html#password-shadow-hash](https://docs.chef.io/resource_user.html#password-shadow-hash)

`MD5`は今から10年以上前から安全性の限界が言われており、`MD5`の使用は躊躇されるところであります。この記事では、SALT付きSHA-512でのパスワードハッシュ生成方法を紹介します。

## 実装例

`unix-crypt` という`gem`を利用します。
https://rubygems.org/gems/unix-crypt/versions/1.3.0

chef-client が使うrubyにgemをインストールする方法については別記事で紹介します。

### sample recipe

```ruby
require 'unix_crypt'

passwd   = "theplaintextpassword"
salt     = rand(36**16).to_s(36)
hashpass = UnixCrypt::SHA512.build(passwd, salt)

user "testuser01" do
  password hashpass
end
```

上記のrecipeで生成されたパスワードハッシュは `/etc/shadow` に格納されています。

```shell-session
$ grep testuser01 /etc/shadow
testuser01:$6$jf9jczpytkqh4d8d$cyeYxVzXZqXOdcaBFIEj4AB1u8jDKsTOdNZCtOq5EJQ09F6cdRcQg8Xril1iR5Rl4R3wzkyXlK.TM5roXyyDV1:17772:0:99999:7:::
```

このサンプルレシピは毎回ハッシュを生成するため、同じパスワード文字列を使っていても毎回`user`リソースが実行されることにご注意ください。

## 補足

### SALT付きSHA-256でハッシュ化する場合

`UnixCrypt::SHA512` から `UnixCrypt::SHA256` への変更に加え、SALTを16桁から8桁に変更します。

```ruby
require 'unix_crypt'

passwd   = "theplaintextpassword"
salt     = rand(36**8).to_s(36)
hashpass = UnixCrypt::SHA256.build(passwd, salt)

user "testuser01" do
  password hashpass
end
```

ちゃんとハッシュの冒頭が `$5$` になっていることが確認できます。

```shell-session
$ grep testuser01 /etc/shadow
testuser01:$5$ma1rnyvi$77zJduFMQkEMHTurexnpCB.grZA/5b8xPFyRQZIb.MA:17772:0:99999:7:::
```

### CentOS7でデフォルトのハッシュ化方式を変更・確認する

`/etc/pam.d/system-auth`を直接確認・変更するより、`authconfig`コマンドを使用するほうが推奨されるようです。

```shell-session
$ authconfig --test | grep hashing
 password hashing algorithm is sha512
$ authconfig --passalgo=sha256 --update
$ authconfig --test | grep hashing
 password hashing algorithm is sha256
```

### 参考
[Chefと/etc/shadowとRuby](http://techs-empty.tumblr.com/post/14348640038/chef%E3%81%A8etcshadow%E3%81%A8ruby)
Built-in Shrinkerがproguard-rulesのパースに失敗する

### ※ Built-in Shrinkerは、Android Gradle Plugin 3.3からR8に置き換わりました。

## 問題

Built-in Shrinkerを有効にしてビルドしたときになぜか

```
> ProGuard configuration parser error: ~\app\proguard-rules.pro line 35:21 no viable alternative at input ','
```

こんなビルドエラーが表示されました。
`useProguard true`は問題ないので、`proguard-rules`の記述は間違っていないはず…

ちなみに発生環境は`Android Studio 3.1.4`です。
(この問題自体をShrinkerを諦めることで長らく放置してたので、3.1.0でも起きると思います。)


## なおった

結論だけ言うと、proguard定義の

```
-keepmembernames,allowobfuscation
```

はダメで

```
-keepmembers,allowshrinking,allowobfuscation
```

なら通ります。

「`,` is 何？」みたいなパースエラーが吐かれますが、嘘です。
**`allowshrinking`オプションを省略記述にした上で`allowobfuscation`オプションを使うとエラーになります。[^1]**

僕の場合、**ライブラリが公開しているproguard定義**をそのまま書いたら、この記述を使っていてShrinkerがエラーになっていました。


[^1]: `-keep*names`は`-keep*s,allowshrinking`の省略です。`-keepmembernames`は`-keepmembers,allowshrinking`の省略にあたります。
MacでQGIS3系をインストールする際のPythonバージョン問題

MacでQGIS3系をインストールするにあたって、pythonのバージョンなどで困った点とその解決法に関する覚え書きです。

###環境
Mac OS X 10.11
QGIS 3.2.2 Bonn
python 3.6.6（python2.7やpython3.7もこれ以前にインストール済み）

###QGIS3系とpython3系
Macにはデフォルトでpython2系がインストールされていますが、それに加えてpython3系をインストールしているユーザーは多いと思います。そしてQGIS3系のインストールの場合、この記事の執筆時点ではpython3.6が要求されるため、これ以外のバージョンだとインストールに失敗してしまいます。
このバージョン起因のインストールエラーが意外と厄介だったりします。

- pyenvを使わない／使いたくない人向け

pythonのバージョン管理について調べるとpyenvを使って管理する方法が検索でよくヒットしますが、それ以外の方法についてはあまり書かれていなかったので今回記事にしました。初学者向けです。
QGISのアプリケーションがどこを参照してpythonのバージョンを判定しているのかわかりませんが、たぶんpyenvを使ってglobalに3.6系でバージョン指定してあげれば、QGIS3系のインストールもできる気がします（試していませんが）。

###インストール方法

1. 全体の流れ
[QGISのウェブサイト](https://qgis.org/en/site/index.html)からdmgファイルをダウンロードします。ディスクイメージを開くと色々ファイルが出てくるので、指定バージョンのpythonがインストール済みであれば、GDAL => QGIS　の順で各インストーラー（.pkg）をクリックしてインストールすればOKです。スムーズにいけばこれだけでインストールが完了します。
尚、GDALやQGISのインストーラーを普通にダブルクリックすると「開発元が未確認のため開けません」と出てきますが、右クリックまたはControlキー+クリックから開くと先に進めます。

2. pythonのバージョン違いによるエラーについて
しかし、pythonのバージョンが指定されたもの以外だと、QGISのインストールで失敗します。python3系がインストールされていなかったり、3系だけど指定以外（今回の場合は3.6以外）が入っていたり、参照箇所が異なっていたりするとエラーになります。当たり前とはいえ、結構シビアです。
ちなみにHomebrewでpython3.6系がインストール済みであっても失敗することがあり、私の場合はターミナルで python3 -V と打つとpython3.6.6 と表示されているにも関わらず「python3.6をインストールしてください」的なエラーメッセージが流れていました。

3. 指定されたバージョンのpythonをインストールする
もしpythonのバージョンでエラーが出た場合、指定されたバージョンのpythonをインストールする必要があります。
前述の通りpyenvでバージョン指定を行う方法でもいけるかと思いますが、私の場合は、**[python公式ページ](https://www.python.org/downloads/)から3.6系のインストーラーパッケージをダウンロードしてインストールする**ことでうまくいきました。これが最もシンプルで失敗のないやり方な気がします。
ただし、別用途でpython3.7以上を使いたい場合やバージョン管理を行いたい場合はpyenvを用いて切り替えながら使うことになるのかなと思います。

3. GDALからインストールし直す
QGISのインストールで失敗し、python3を入れ直して再トライした場合、QGISインストールに成功しても、ソフトを開いた際に一部のプラグインの読み込みに失敗するエラーが生じることがあります（"Couldn't load plugin 〜 "）。
これは、正しいpythonバージョンにてGDALのインストールが行われなかったことに起因するものです。
あくまでインストールは、python3.6 => GDAL => QGIS の順番で行われなければなりません。ただし、逐一アンインストールするまでもなく、GDALとQGISをそれぞれ同じように上書きインストールすればOKのようです。

###まとめ
QGIS3系のインストールでつまづいたのでメモとして書きましたが、同じようなエラーで困っている方の一助となれば幸いです。
Windowsでは問題なくインストールできたのですが、Macの場合デフォルトでPython2系が入っていることや、インストール方法によって参照場所が異なっていたりしてややこしいですね。
これからMac上でQGIS3系を色々と試してみたいと思います。
結構バグや不安定な動きが多く、しばらくは試行錯誤が続きそうな気がします。
Mac と Debian stretch とで Jest の coverage 結果が違った話

## 概要

ある開発中プロジェクトで、これまで JS のテストカバレッジを活用出来ていなかったため軽い気持ちでやっていきをしたら、
開発環境では設定した閾値を越えるのに CI 上ではパスしないためデプロイできないという状況が起こりました。

## 環境

- 開発マシン
  - OS: maxOS 10.12.6
  - Node.js: 10.8.0
  - npm: 6.3.0
- CI (Wercker)
  - OS: Debian stretch-slim
  - Node.js: 8.x
  - npm: 6.x

どちらも Jest のバージョンは `23.4.1` を利用しており、
設定も `package.json` に記述しているため共通のものを利用しています。
また、カバレッジに関する設定は閾値の設定しか行っていません。

Jest 実行時のコマンドは以下。

```sh
jest ./resources/assets/js --no-cache --coverage
```

## 結果

- 閾値を設定したままデプロイ出来るようになりました。
- 開発環境、CI環境のカバレッジが一致するようになりました。
  - カバー率が一致しなかったのは、実行するテストコード自体が 100% でカバレッジに含まれてしまっていたためでした。
  - macOS でテストコードの分が計上されていた事と、反対に Debian 環境上では計上されなかった事の理由は調べられていません。ご存知もしくは心当たりのある方がいらしたら教えてください :pray:

## やったこと

Node.js のバージョンを合わせてみたりしましたが、関係無いようでした。
最終的に `package.json` の Jest の設定に以下を追加しました。

**`coveragePathIgnorePatterns` [array]**
https://jestjs.io/docs/en/configuration.html#coveragepathignorepatterns-array-string

```json
{
  "jest": {
    "coveragePathIgnorePatterns": [
      "__tests__",
      "\\.spec\\.js",
      "\\.spec\\.ts"
    ]
  }
}
```

フォーマットは正規表現っぽいんでもうちょっと綺麗に出来るんじゃないかなぁと思います。
SQLインジェクションとは

# SQLインジェクションとは

アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。 

例えば以下のような`users`テーブルがあるとする。


|ID|password|
|---|---|
|ito|ito|
|sato|sato|
|kimura|kimura|
|motomura|motomura|

```sql
SELECT * FROM users WHERE ID = '{$userId}' AND password = '{$passwd}'
```

上記SQLにより`users`テーブルでのレコードの存在が確認できればログインができるものとする。
ここで、悪意あるユーザー「sato」が、別ID「kimura」のパスワードを書き換え、不正にログインを試みようとする。

```
$userId
「kimura」
$passwd
「' OR 'A' = 'A」
```

結果、以下のSQLが生成される。

```sql
SELECT * FROM users WHERE ID = 'kimura' AND password = '' OR 'A' = 'A'
```

上記のように常にパスワードが真となるSQLが生成され、不正ログインを許容することになる。
このように、何かしらの処理で生成されるSQLを悪用し、不正ログインを行ったりDB内容を書き換えたりすることをSQLインジェクションという。

# 対策

- サーバーでの対策：エスケープ処理の実装でSQL文を成立させない、入力文字の種類や数に制限をかける
- ネットワークでの対策：ファイアウォールの導入など、脆弱性を狙った攻撃を検知するソリューションを導入する
- 実装時の対策：エスケープ構文を使用して特殊文字をエスケープする、クエリ内でLIMIT句やその他のSQL制御を使用することで、SQL
インジェクション攻撃が発生した場合のレコードの大量漏洩を防ぐ、など。

参考：https://www.owasp.org/images/2/23/OWASP_Top_10-2017%28ja%29.pdf

※ ちなみに`ruby_on_rails`では、特殊なSQL文字をフィルタする仕組みがビルドインで備わっている。その他対策は下記参照。
https://railsguides.jp/security.html#%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3
Gravatar: Generate ProfilePhoto

Random:
http://www.gravatar.com/avatar/47?s=100&d=wavatar
・47：random number,　mailかidなどはmd5で暗号化した情報も利用できる
　　　mailがGravatar.comにすでに登録した場合、アップロードされた画像を取得する
・100：画像のサイズ（100：100＊100）
・wavatar：画像のスタイル　identicon、monsterid、wavatar、retro、robohash も使える

Image Requests
　・https://cn.gravatar.com/site/implement/images/

Profile
　・https://cn.gravatar.com/site/implement/profiles/

from : http://www.bretwang.com/archives/381
Redis Cluster では完全な keys *が使えない

> redis-cli -c -h cluster-host keys '*' |wc -l

このコマンドの挙動をRedis Clusterにある全てのオブジェクト数をカウントできるかと思っていた。
実際そうではなく、返ってくるのは cluster-host の全オブジェクト数であって他のシャードにあるオブジェクトは検索対象外。

理屈は
オブジェクトを配置する際 key の hash値 から SLOT を計算するので、検索キーが曖昧だとどのシャードにいるか判断できないから。

勉強になった。

【参考URL】
https://qiita.com/sawada_masahiko/items/c58ff2953e04c2956c6f
LINUX KERNEL DEVELOPMENTを読む（１）

LINUX KERNEL DEVELOPMENTを読んだ.色々気になったステートメントについて書いていきます。

https://www.amazon.co.jp/Linux-Kernel-Development-Developers-Library/dp/0672329468/

##Introduction to the Linux Kernel

* この章では、Linuxカーネルと、LinuxOSについて紹介する。
* 今日、Unixとは、一ファミリーのOSであり、似たようなAPIと、共有されたデザイン決定を持っている。

いか、Unixの歴史について書いていきます。

*  ４０年に渡る使用の歴史により、Unixは、現在存在する中でもっともパワフルでエレガントなOSだと、コンピュータ学者は思うようになった。

Unixの他に存在するOSといえば、Windows OS、トロン、ぐらいしか知らないですが、Max OSやLinuxもUnixだとすると、もしかしたらもっともパワフルでエレガントなOSかもしれないですね。
この後、Multicsの歴史に触れていっているようです。Multicsはベル研で開発されたもののようですね。

*  1969年の夏、ベル研のプログラマーは、Unixに進歩するファイルシステムのデザインを考案した。
*  1973年、OSはCによって書き直された。未曾有の変更だったが、将来の移植性に寄与した。  
LinuxやFreeBSDは今でもC言語によって書かれていますが、ここから始まったんですね。それ以前は恐らくアセンブラや機械語などで書かれていたんだと思います。アセンブラや機械語は全然移植性がないですね。C言語はそれに対して、ほとんどのアーキテクチャーで使えるので、移植性を担保するにはいい選択だと思います。今では当たり前だと思うんですが、当時は未曾有だったんですね。

*  Unixの設計のシンプルさは、ソースコードと一緒に配布されていると言う事実と並んで、さらなる発展を導いた。

オープンソースの思想が当時からあったんですね。Unixの設計はシンプルだと思いますが、ソースコードは今や相当に巨大になってます。

*  もっとも影響のある貢献者は、カリフォルニア大学バークレー校だった。
Free BSDのこと言ってるのかなと思います。
*  バークレーの最初のリリース、1BSDは、1977年だった。

結構古いですね。僕が生まれる２年前だ（年齢がバレる）
その後、BSDの歴史が続きます。

*  最初のスタンドアローンのバークレーのUnixは、3BSDで、1979年だ。仮想メモリ（Virtual Memory)が機能のリストに加えられた。

仮想メモリが出てきました。仮想メモリとは、最近使われることがあるのかわからないですが、ハードディスクの一部をメモリとして使う機能のことです。昔のPCだと結構使ってたかもしれません。

*  そのあとのリリースで、ジョブコントロール、デマンドページング、TCP/IPなどが付加された。

TCP/IP結構古いですね。ジョブコントロールとは、ユーザがプログラムの実行状態や周辺機器との接続状態をコントロールすることのようです。今では当たり前に見えるんですけどね。

*  1980年代から1990年代にかけて、たくさんのワークステーション会社やサーバー会社が商用バージョンのUnixをリリースした。これらのシステムは、AT&Tかバークレーのリリースをベースにしており、特定のハードウェアアーキテクチャーによってサポートされている。

このあと、Unixはシンプルである理由が述べられています。
理由１、普通のOSは何千もの明確でないシステムコールがあること、それに対し、Unixは数百であること。
理由２、Unixは全てのものがファイルであること。
理由３、UnixはCで記述されていること」
理由４、Unixは非常に早いプロセス生成時間を持っており、ユニークなfork()システムコールを持っている。
理由５、Unixはシンプルで頑健なプロセス間通信(Interprocess communication)を持っている。

そして、Unixはマルチタスク、マルチスレッディング、仮想メモリ、デマンドページング、デマンドローディングによる共有ライブラリ、そして、TCP/IPネットワークを持っている。

そして、Linuxシステムへと続きます。

##Along came Linus:Intruduction to Linux

*  Linuxの最初のバージョンは、1991年。リーナスは、パワフルでフリーなUnixがないことに困っていた。
*  なんかDOSはゲームする以外に使いにくい。
*  Minixはライセンスのせいで再配布できない。
*  で、リーナスは自分自身のOSを書くことにした。
*  で、1991年の終わりに、リーナスはインターネットに早期のバージョンをリリースした。
*  ポストしたら、ものすごくブレークした。
*  今日、Linuxは様々なアーキテクチャーに使われている。スマホから、スパコンまで。  


個人的にこれ見て思うことが、やっぱり自分が必要とするものを作るって重要なんだなと思います。逆に言うと、自分が必要としないものを作っても仕方ないんですよね。

* LinuxはUnixのようなシステムだが、Unixではない。それはどう言うことかと言うと、LinuxはUnixやUnixのAPIからいろんなアイディアを借りてきているが、他のUnixシステムのように、ソースコードは、Unixの子孫ではない。

なるほど、Mac OSはUnixのソースコードを使っていて、LinuxはUnixのソースコードを使っていないと言うことになるのか。

*  Linuxは、GNU General Public License（GPL) version 2.0によってライセンスされている。なので、ただでダウンロードできるし、改良を加えることができる。
*  Linuxの基本はカーネル、Cライブラリ、ツールチェイン、そして基本Utility、例えばログインプロセスとシェルである。
*  今後、Linuxカーネルと言う時は、明示的にLinuxの全システムを指すのか、カーネルを指すのか正確に指定しようと思う。正確に言うと、Linuxはカーネルのことを指す。

言語を明確に定義するのは外人さんらしいですね。この本はLinuxカーネルに関する本なので、Linuxの基本のうちの一つ、Linuxカーネルについて掘り下げていくことになりそうです。
Node.jsでローカルホストサーバーをたてる

##モジュール
使用したNode.jsのモジュール
・http
・fs

##コード1

```javascript:postString.js
const http = require("http");
const server = http.createServer();

server.on("request", function(req, res){
  res.writeHead(200, {"Content-Type": "text/plain"});
  res.write("hello");
  res.write("world");
  res.end();
});
server.listen(8080);
```

httpモジュールをインポートし、サーバーを作成する。
server.onでサーバーの設定をする。
server.listen(8080)でサーバーを起動する。

##コード2

このコードは、HTMLを表示できる。
ここでは、以下のようなディレクトリ構成にする。

```
root
  ├postHTML.js
  └index.html
```

```javascript:postHTML.js
const fs = require("fs");
const http = require("http");
const server = http.createServer();

fs.readFile("./index.html", function(err, data){
  if(err){
    console.log("reading error");
  }else{
    server.on("request", function(req, res){
      res.writeHead(200, {"Content-Type": "text/html"});
      res.write(data);
      res.end();
    });
  }
});

server.listen(8080);
```
[Ubuntu] Azure Storage accountのFile共有をcifs経由でオートマウント

# これはなに？

Azure File共有(SMB 3.0でアクセスできるやつ)をUbuntuに自動マウントさせました。

# 環境

- Azure Storage account
- Azure Virtual Machine
- OS: Ubuntu 18.04

# `autofs`の設定

## インストール

`autofs`をインストールします。

```shell-session
sudo apt-get install autofs
```

## 設定ファイルの作成

`/etc/auto.master`に読み込ませるファイルを作ります。
ファイル名は適宜。

```shell-session:
sudo mkdir /etc/auto.master.d
sudo vi /etc/auto.master.d/tracker-backup.autofs
```

中身はこんなんです。

```text:/etc/auto.master.d/tracker-backup.autofs
/-      /etc/auto.tracker-backup
```

マップファイルを作成します。

```shell-session
sudo vi /etc/auto.tracker-backup
```

中身はこんなんです。

```text:/etc/auto.tracker-backup
/backup         -fstype=cifs,vers=3.0,username=ユーザ名,password=パスワード,dir_mode=0777,file_mode=0777,sec=ntlmssp              ://ストレージアカウント名.file.core.windows.net/tracker-backup
```

`/-`としてダイレクトマップにしたので、先頭の要素はキーではなく絶対パスを書きます。

パスワードが書いてあるので、ファイルパーミションを変更します。

```
sudo chmod 600 /etc/auto.tracker-backup
```


----

:notebook_with_decorative_cover: ノート

長々としたオプションは、Azureポータルから確認できます。

ストレージアカウントを開き、ファイルストレージを選択します。端の…をクリックして[Connect]メニューを選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/8b41098f-ef00-0b9a-eeba-d684e578bdd2.png)

そうすると、以下のようなものが表示されるので、ここからコピペします。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/c1fe534f-efec-7347-9521-c65442aaaeb3.png)

----


## `autofs`を再起動

```shell-session
sudo systemctl reload autofs
```


# 確認

`mount`コマンドでマウントされているか確認します。

```shell-session
ls /backup
mount
```

ファイルを作ってみます。

```
touch /backup/hoge
```

Azureポータルで見てみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/a253224f-0f7f-4997-3f0e-d441ffe888bb.png)

できていました。
collectionviewでcellが一つしか表示されない問題

# そりゃそうなるか
って感じのミスだったのですが、同じことをうっかりやる人がいかねないのでここに記します。

# cell.frameに値を手動で突っ込んだ
cell.frameはcollectionViewを親とするframe。
だから全てのcell.frameに一定の値を入れると、**全部重なって一つしかcellが表示されていないように見えます**。
当たり前ですね。

# cellのサイズと位置はcollectionViewのLayoutによって決めよう
cellのframeは直接指定するのではなく、それを持つcollectionViewのLayout機能に任せましょう
(なんならもとよりcollectionViewはcellのframeを計算する機能がメインだろアホか僕…)
Layoutに関しては下の記事が非常にわかりやすく汎用的に書いてくれていたのでこちらを読むのが良いでしょう。
https://techlife.cookpad.com/entry/2017/06/29/190000

# 以上現場からでした
（´-`）.｡oO（同じことする人いるのかなぁ
yarn reinstall

## before
```bash
rm -rf node_modules
yarn 
```

いちいちnode_modulesフォルダをrmコマンドで削除したくない。

## after
```bash
yarn install --check-files
```

これでOk。
> [node.js - How do I force Yarn to reinstall a package? - Stack Overflow](https://stackoverflow.com/questions/41864099/how-do-i-force-yarn-to-reinstall-a-package)
PHP7におけるタイプヒンティングにて発生した例外をcatchする

呼び出し元

```php
	try{
		$users = $this->users->fetch_users($id);
	}catch (TypeError $e){
		echo $e->getMessage();
	}
```

呼び出し先

```php
	public function fetch_users(int $id)
	{
		    $sql = "SELECT * FROM users WHERE id = ?"; //
		    $users= $this->db->query($sql, $id);
		    return $users;
	}
```
結果
`Argument 1 passed to XXX::fetch_users() must be of the type integer, string given, called in XXX/xxx/xxx/xxx.php on line `

なお本例のようにint型を指定しても、「1abcd」など数値始まりの文字列が渡された場合、異なったエラーが発生し補足できない模様
Nimでテキストの表を出力

## 概要

ここ最近はNim離れしていたので、リハビリ＆思い出しながら、書いてみました。
２次元配列の(文字列)データを、テキスト表形式で出力します。

## ソース

```nim
import strutils,sequtils
import unicode,nre,options

proc display_length( text: string) : int =
    let rune_text = text.toRunes
    let text_len = rune_text.len

    for i in 0..<text_len:
        let c = $rune_text[i]
        # by http://orange-factory.com/sample/utf8/code3/ef.html#HalfwidthandFullwidthForms 
        if c.match(re"(*U)[ｦ-ﾟ]").isSome:
            result += 1
        elif c.match(re"^[^\x01-\x7E\xA1-\xDF]").isSome :
            result += 2
        else:
            result += 1

proc out_table( rows: openArray[seq[string]]) : string =
    assert( rows.len >= 2 )
    assert( rows[0].len > 0 )

    # 各カラムの長さを計算
    var col_len_max: seq[int] = repeat(0, rows[0].len)
    for cols in rows:
        for i in 0..<cols.len:
            let col_len = cols[i].display_length
            if col_len > col_len_max[i]:
                col_len_max[i] = col_len

    # カラムの幅を＋１する
    col_len_max.apply( proc (len: var int) = len += 1)

    # 水平の線を作成
    var horizon_line: seq[string] = @["+"]
    for i in 0..<rows[0].len:
        horizon_line.add(repeat("-",col_len_max[i]).join(""))
        horizon_line.add("+")
    let horizon = horizon_line.join("")

    # 結果格納用
    var newTable: seq[string] = @[ horizon ]

    # １行ずつ出力する
    var row_num = 0
    for cols in rows:
        var newCols: seq[string] = @[""]
        for i in 0..<cols.len:
            let len_max = col_len_max[i]
            let col_len = cols[i].display_length
            newCols.add (cols[i] & repeat(" ", len_max - col_len).join(""))
        newCols.add("")

        newTable.add( newCols.join("|") )
        # １行目出力後に、横線を追加する
        if row_num == 0:
            newTable.add( horizon )
        row_num += 1

    newTable.add( horizon )
    result = newTable.join("\n")


let text = """
abc,abcd
def,defff
ghi,ghiiiji
あいう,あいうえお
かきく,かきくけこ
さしす,ｻｼｽｾｿ"""

let lines = text.splitLines()
var table: seq[seq[string]] = @[]

for line in lines:
    let row: seq[string] = line.split(",")
    table.add( row )

echo out_table( table )

```

### 結果

![Screenshot from 2018-08-29 13-38-16.png](https://qiita-image-store.s3.amazonaws.com/0/58872/98f50677-e170-763e-2419-ce1f95fa8c42.png)
Dynamics　バージョンアップに関する変更点

##バージョンアップに関する変更
Dynamics365のバージョンアップに関して、大きな変更があるようです。


以下のページに記事が掲載されています。

■Dynamics 365 のアップデート方法を刷新
https://community.dynamics.com/b/dynamicsblog-ja-jp/archive/2018/07/11/modernizing-the-way-we-update-dynamics-365

■Dynamics 365 Customer Engagement (オンライン) のバージョンに関する重要なお知らせ
https://blogs.msdn.microsoft.com/crmjapan/2018/07/19/dynamics-365-ce-online-important-notice-about-versioning/


重要そうなところを抜粋すると・・・

●すべてのユーザーが同じバージョンを利用
●アップグレードコストの削減
　→これまでのユーザーの好きなタイミングでのアップデートではなく強制アップデートっぽい
●4 月と 10 月の年 2 回のメジャーリリースを通じて新機能が提供
●下位互換性あり
●ユーザーエクスペリエンスに大幅な影響があるような新機能については、既定でオフになっているので、必要に応じて有効化が可能
●プログラムのリリース前にサンドボックス環境でメジャーアップデートの検証が可能

もう少し、詳細な手順とか欲しいところです。
今後の情報公開を待つことにします。




##※旧バージョン利用中の場合の注意事項
●バージョン 8.1
　2 月から 7 月 31 日 の期間内に最新バージョンへの更新が必要
●バージョン 8.2
　2019 年 1 月 31 日までに最新バージョンへの更新が必要
[小ネタ] Haskellでモンティ・ホール問題を解いてみよう

今回はHaskellでモンティ・ホール問題を解いてみようと思います。すごいH本を読破した方であれば理解可能なコードになったと思います。

## モンティー・ホール問題とは
[Wikipediaより](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%A3%E3%83%BB%E3%83%9B%E3%83%BC%E3%83%AB%E5%95%8F%E9%A1%8C)
> モンティ・ホール問題（モンティ・ホールもんだい、英: Monty Hall problem）とは、確率論の問題で、ベイズの定理における事後確率、あるいは主観確率の例題のひとつとなっている。モンティ・ホール（英語版） (Monty Hall, 本名 Monte Halperin) が司会者を務めるアメリカのゲームショー番組、「Let's make a deal（英語版）[1]」の中で行われたゲームに関する論争に由来する。

## 概要
クイズの概要は至ってシンプルです
> 「プレーヤーの前に閉まった3つのドアがあって、1つのドアの後ろには景品の新車が、2つのドアの後ろには、はずれを意味するヤギがいる。プレーヤーは新車のドアを当てると新車がもらえる。プレーヤーが1つのドアを選択した後、司会のモンティが残りのドアのうちヤギがいるドアを開けてヤギを見せる。ここでプレーヤーは、最初に選んだドアを、残っている開けられていないドアに変更してもよいと言われる。プレーヤーはドアを変更すべきだろうか？」

ここで処理の流れをまとめると：
1. ヤギ２頭、車の順番を1つランダムに選択する。
2. プレイヤーはランダムに扉を1つ選択する
3. モンティーは残った２つの扉からヤギのものを選択し、開ける
4. 残り1つの扉（すなわち変更したときの扉)が車であるか調べる

#### メモ

- ヤギ、車は`Prize`型を定義し、それを用いて表現する
- 2~4に関してはリスト内包表記を用いればエレガントに求めることができる
- クイズをn回反復して行うには`replicateM`を用いる
- 確率はそのまんまです。(扉を変えたときに車であった回数 / クイズを行った総数)

```haskell
module Lib
    ( montyHall
    , runMontyHall
    ) where

import           Control.Monad (replicateM)
import           Data.Semigroup ((<>))
import           System.Random (randomRIO)

-- | Given an list, picks an element
pick :: [a] -> IO a
pick xs = do
    ele <- randomRIO (0, length xs - 1)
    return $ xs !! ele

-- | Prizes from Monty Hall
data Prize =
      Goat
    | Car
    deriving (Eq, Show)

-- | Run monty hall
montyHall :: IO Bool
montyHall = do
    prize  <- pick [[Car, Goat, Goat], [Goat, Car, Goat], [Goat, Goat, Car]]
    choose <- pick [0 .. 2]
    monty  <- pick [ i | i <- [0 .. 2], i /= choose, prize !! i == Goat ]
    let switch = head [ i | i <- [0 .. 2], i /= choose, i /= monty ]
    return $ prize !! switch == Car

-- | Run @'montyHall'@ given number of times and compute it's winning percentage
runMontyHall :: Int -> IO ()
runMontyHall num = do
    putStrLn $ "Running monty hall " <> show num <> " times"

    -- Run the computation
    xs <- replicateM num montyHall
    let winning = filter (== True) xs
    -- Compute the winning percentage
    let winningPercentage = fromIntegral (length winning) / fromIntegral num * 1000
    let winningPercentageRound = fromIntegral (ceiling winningPercentage) / 10

    -- Print the results
    putStrLn "Computation is done!"
    putStrLn $ "Chance of winning a car is " <> show winningPercentageRound <> "%"
```

## 扉を変えたほうがいいのか

それではモンティ・ホールを10000回ほど行い、その確率を求めてみましょう。

```terminal
*Main Lib> runMontyHall 100000
Running monty hall 100000 times
Computation is done!
Chance of winning a car is 66.7%
```

ちなみに扉を変えなかった場合に当たる確率は約33％でした。よって扉を変えたほうが車が当たる確率は変えなかったときに比べて約2倍になります。
ゼロから作るDeep Learningメモ

#MNISTデータセット読み込みでの書籍との相違点
書籍の中では
sys.path.append(os.pardir)
となっているが、私自身のWindowsの環境ではできなかったので
sys.path.append("C:\\\Users\\\name\\\Documents\\\deep-learning")
というように記述してみたらエラーがなくなりデータセットの読み込みを行えた。

#ニューラルネットワークの推論処理
HPからDLしたディレクトリに入っているneuralnet_mnist.pyを実行すると成功するが、自分で作ったディレクトリでsys.path.append("")の部分を変更しただけでは実行できなかった。

Traceback (most recent call last):
  File "neuralnet_mnist.py", line 33, in <module>
    network = init_network()
  File "neuralnet_mnist.py", line 14, in init_network
    with open("sample_weight.pkl",'rb') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'sample_weight.pkl'


といったエラーメッセージが表示された。
そこでinin_network()関数の中を
    with open("C:\\\Users\\\username\\\Documents\\\pro\\\deep-learning\\\ch03\\\sample_weight.pkl",'rb') as f:
と記述し直したらエラーが消え、正常に実行された。
Pythonのインタラクティブモードで編集中のモジュールを再読み込みしたい

## やりたいこと

今回のやりたいことは、表題の通りです。
(淡々と書きますので、ご容赦を...)

### なぜやりたいの？

現在、「小さく関数を作ってつなぎ合わせて大きいものを作る」ということを意識して、コツコツと学習をしています。
インタラクティブモードで動作確認をしつつ、エディタ側のソースコードに反映させていくという流れで取り組んでいます。

さて、実際にソースコードの変更をしたので、起動中のpythonのコンソールから、変更の内容、動作確認をしたい...となったとき。

Railsだとconsoleで同じように確認していて、reload! とすると再読み込みしてくれるので、同じようなことがしたい...。
ただしフレームワークを使ったものではなく、単体のスクリプトなので、どうしたものかと調べていました。

## とりあえずやってみたこと

こんなコードを用意します。

```python
class Greeting:
    def hello(self):
        print("Hello World!")

def try_greeting(method_name='hello'):
    greeting = Greeting()
    if method_name is None:
        method_name = 'hello'

    eval('greeting.' + method_name)()

def main():
  try_greeting()

if __name__== "__main__":
  main()
```

まずは直接pythonコマンドにソースコードを渡して、簡単に動かしてみます。

```bash
$ python sample.py 
Hello World!
```

つぎに -i オプションで、インタラクティブモードで呼び出して動かしてみます。

```python
$ python -i sample.py 
Hello World!
>>> main()
Hello World!
```

今度は、引数無しで起動します。

```python

>>> import sample
>>> sample.main()
Hello World!

# このあと、エディタ側で print("こんにちは!")に書き換えてsave
# でも変わらない...
>>> sample.main()
Hello World!

# importlibを使って再読み込みさせます

>>> import importlib
>>> importlib.reload(sample)
<module 'sample' from '/Users/akiko/work/convert_qiita/sample.py'>

# こんどは反映されました
>>> sample.main()
こんにちは!
```

### クラスも試します

同じインタラクティブモードのまま。

```python
# 書き換えた状態でGreetingのインスタンスを作成
>>> g = sample.Greeting()
>>> g.hello()
こんにちは!!!!

# このあと、print("こんにちは!!! うまくできてますか？")  に書き換え
>>> importlib.reload(sample)
<module 'sample' from '/Users/akiko/work/convert_qiita/sample.py'>

# 再読み込みをさせますが、すでにインスタンス化されているものは、メソッドは変更が反映されません
>>> g.hello()
こんにちは!!!!

# 追加で新しく作ったほうは、変更が反映されています
>>> g2 = sample.Greeting()
>>> g2.hello()
こんにちは!!! うまくできてますか？

```

## まとめ

簡単ですが、うまくいきました。
ただし、上記で試したとおり、クラス利用の場合は挙動に注意。
また、再読み込みする前に生成されたオブジェクトや変数は、変更が適用されていませんので注意。

## 補足

少し前に、こういうメモを上げましたが、こちらの方法でいけそうかな？

- [Python3 覚え書き: インタラクティブモードで pythonスクリプト (main) を実行するには？](https://qiita.com/akiko-pusu/items/1f802353fcc73bec877a)
CRM/CTIシステムのコストダウン

#CTIをひかり電話で構築すると、ナンバーズディスプレイ利用料が必要になります。
##無料にならないのかな？と、思っていたけど・・・

##IP電話(050)を使用すると発信者の電話番号が表示されます。

イニシャル無料、月額基本料金無料の 050 番号から、FUSION IP-Phone を使用してみました。
brastel も候補にしたのですが、最初にチャージが必要です。
発信が多い方は、brastel の方が良いと思います。

![FUSION IP-Phone](https://comm.rakuten.co.jp/kojin/ipphone/images/cut01b.jpg)


##副産物、迷惑電話対策
### 着信時に迷惑電話が直ぐにわかる。・・・ちょっと( ﾟДﾟ)

アクションURL に、下記を設定。

```
https://www.telnavi.jp/phone/%rid%
```

![アクションURL](https://qiita-image-store.s3.amazonaws.com/0/77496/d134a368-bf08-c03e-179f-8abacfc19fab.png)

### ポップアップするので確認してから出ればOK!!!

![電話番号](https://qiita-image-store.s3.amazonaws.com/0/77496/5ae5dd0a-34be-022d-c410-9ca751a62e67.png)
Swift Weeklyのメモ　Enum iterations in Swift 4.2

https://www.swiftbysundell.com/posts/enum-iterations-in-swift-42/?utm_campaign=Revue%20newsletter&utm_medium=Swift%20Weekly%20Newsletter%20Issue%20128&utm_source=Swift%20Weekly

Swift 4.2 から [CaseIterable](https://developer.apple.com/documentation/swift/caseiterable) というプロトコルが追加されているそうです。
`allCases` をfor文で回すことで、便利に扱えるそう
Zsh — autoload の基本

## autoload で何が出来る？

特定のディレクトリにファイルを置くだけで、**そのファイル名と同じ名前** でコマンドが使えるようになる。
(コマンドの実体はシェルの関数)

## autoload 用のディレクトリを作成

```sh
mkdir -p "$HOME/.zsh/autoload"
```


## ディレクトリを $FPATH に追加する

```sh
export FPATH="$HOME/.zsh/autoload/:$FPATH"
```

## autoload したいファイルを作成する


```sh
echo "echo hello zsh autoload" > "$HOME/.zsh/autoload/hello-zsh-autoload"
```

- ファイル名がコマンド名になる
- 実行権限は必要ない
- ファイル内で関数を作る必要はない

## コマンドを autoload する

```sh
autoload -U hello-zsh-autoload
```

## コマンドが使えるようになる

```sh
$ hello-zsh-autoload
hello zsh autoload
```

## コマンドの実体

 `hello-zsh-autoload` という関数が自動作成されているのが分かる

```sh
$ which hello-zsh-autoload

hello-zsh-autoload () {
	echo hello zsh autoload
}
```

## .zshrc への追加例

```
export FPATH="$HOME/.zsh/autoload/:$FPATH"
autoload -U hello-zsh-autoload
```


## Versions

- zsh 5.5.1 (x86_64-apple-darwin17.5.0)


## Ref.

- [.zshrcで見かけるautoloadの意味と使い方 - Qiita](https://qiita.com/yuku_t/items/77c23390e52168a2754a)
- [9 Functions (zsh)](http://zsh.sourceforge.net/Doc/Release/Functions.html#Functions)

## Links

- [Gist](https://gist.github.com/YumaInaura/20ef6619ed66fa76f7649166bcf3d16e)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
リスク管理始めました

# はじめに

プロジェクトリーダー経験が半年もいかないペーペーがリスク管理を始めた話です。

# おきたこと

ちょっと前にこんなことが起きました

1. メンバーが体調不良で休み(3日)、プロジェクトが遅れた
2. 稼働あげても巻き返せない
3. バッファを使ってリスケする
3. タスク漏れ、手戻りによりさらにスケジュールが遅れる
4. バッファがなくなりリスケできなくなる
5. プロジェクトリーダーがタスクを進める
6. メンバーの高稼働が続く
7. ギリギリ単体テスト完了まではこじつけた
8. 結合テスト仕様書作成中に、テスト実施しきれないことが発覚

そもそも見積りダメじゃんとか、スキル不足とかもろもろ反省点ありますが、お客さんにパツパツ感が伝わっていなかったのが問題。
結果、期限ギリギリ(検品リリース直前)になって調整が入ってしまった。

お客さんとしては状況を正しく把握して、事前に打てる手を打ちたい。
というところから、不安なポイントを洗い出して事前共有するのをリスク管理を通じてやっていきましょう！
というのが経緯。


# リスク管理始めました

「うーんうーん」と頭を悩ませたことや、お客さんレビューで叩かれたこと、などなどはすっ飛ばして今、リスク管理としてやっていることをまとめます。

### リスク一覧に記載すること

こんな情報を取りまとめています。
**リスクの優先度を決め、トラブルを回避・起きてもテンパらない**ための情報がまとめています。

- 起きたらどんな嫌なことが起きるか？（QCDのどれか）
- どのぐらいのダメージがあるか？（影響度）
- どのぐらい起きそうか？（発生確率）
- いつから起きそうか？（発生日）
- どんな予防策があるか？（回避、転嫁、軽減、受容とかは無視してできることを書いた）
- その予防策はいつごろ打てそうか？
- リスクが発生したらどうする

基本的には**「品質に影響があり、直近起きる、影響度が高い」**ものから優先度を高くしています。
※優先度はプロダクトによって異なると思います。

### リスクの考え方（足し方）

基本的に「不安なこと・見えてないこと」はリスクと捉えていいですが、こんな情報があればより漏れがなくなります。

- **スケジュール（ざっくりでも3ヶ月先は入ってる）**
  - リスクを見つけるため、発生日を考えるため
    - 結合、性能テストフェーズが他案件と被っていて環境競合がおきてしまう
    - リリースタイミングなし(お客さん都合でリリース不可)による同時リリース案件数が増える（リリースリスク増）
    - メンバーの入れ替わり、期の変わりはきっと何かある
    - 思ったより仕事がなくて暇しそう、逆に仕事ありすぎて全部出来ない
- **過去から学ぶ（過去のKPTまとめ）**
  - リスクを見つけるため、発生確率、予防策を考えるため
    - 過去どんなことがよく起きているかを参考に、起きやすそうなリスクを考える
    - 過去起きた課題が再発しそうか、または近しい事象が起き得ないか考える
    - 過去起きた課題に対する対策を参考に、予防策を検討する
    - 良いこと(いい意味で予定通りじゃない)もリスク。KEEPもちゃんと見直す
- **メンバーヒアリング**
  - リスクを見つけるため、QCD 、影響度 、予防策を考えるため
    - 困るのはみんななので、どれが困るか、どうすると嬉しいか、の意見を大切にしている
    - 予防策打つのはみんななので、どんなことなら出来そうか、いつ出来そうか、の意見を大切にしている
    - 新しい気づきがあってリスクが増えることも多々ある


### リスクを見直す

毎週月、金にリスク一覧を見直しています。
肝心なのは**「定期的に見直す」**こと。
個人的な印象ですが、1週間あれば状況はガラッと変わります。

やることはシンプルです。

- 上記の「リスクの考え方」にそってリスクを追加する
- 再度、優先度を見直す
- 課題になったリスクがあるか確認する
- 予防策の状況確認する

# 結果〜4つの効果〜

### ①先を見通せるようになった

ひとつひとつの案件だけではなく、その先、今年度中のスケジュール(ざっくりだけど)が見えるようになった。
いろんな情報が事前に分かるようになり、こちらから「いつまでに決めてもらえないと出来ないですよ」と打ちだせるようになった。
結果、お客さんからの納期ギリギリを攻めるような要望が少なくった。
※残念ながら無くなってはない。

### ②メンバーの課題に事前アプローチできるようになった

メンバーの抱える不安(リスク・課題)に気づけるようになり、そこへ前もってアプローチ出来るようになった。
結果、メンバーの進捗(生産性)が良くなった。

### ③過去の問題点を繰り返さなくなった

週次で「過去から学ぶ(KPTまとめ)」を見直すことにより、「こんな課題起きてたんだ。あれ？今回大丈夫？」となり過去起きた事象に近いことをチェックする(リスクと捉える)ようになった。
結果、トラブル数が減り、心の余裕が増えた。

### ④僕の勤務時間が増えた

良くないことですね・・・
やらねばならないことに気づき対策しているので、単純にやることが増えました。
やり方を工夫しないとね。って状態です。


# おわりに

これはリスク管理というのか・・・感じがしますが、過去の失敗を活かして良い感じ！になっているので良しとしてます。

PMBOK的には、リスクマネジメント計画書を作って、リスクの影響、発生率、などを定量的に測れるように定義しなさい。ってなっているようですね。
今回は完全我流でやってしまいました・・・

今後は、そのようなことも参考にしつつ、誰でもできる形に持っていきたいです。
僕が楽するためにも。
curlで公開済みGoogle Driveデータを超簡単にダウンロードする

# tl;dr
これだけ

```bash
curl gdrive.sh | bash -s <FILE_ID>
```
でダウンロードすることができます。

# やりかた
## 📎 共有可能なリンクを取得
![aaaa.png](https://qiita-image-store.s3.amazonaws.com/0/107399/aa14d3e2-951d-9147-d833-270541a54707.png)

## リンクをコピー
![aaaa.png](https://qiita-image-store.s3.amazonaws.com/0/107399/0d8297e7-fc80-095d-1fb8-359f499db21d.png)

## リンクを貼り付け
```bash
curl gdrive.sh | bash -s https://drive.google.com/open?id=0B4y35FiV1wh7QVR6VXJ5dWExSTQ
```

## おわり
Google Colaboratoryでデータセットとかダウンロードしたいけど、 **[gdrive](https://github.com/prasmussen/gdrive)** とか **[DriveAPI](https://developers.google.com/drive/)** をインストールしたり、調べたり認証するのめんどくせーと思ってる人はぜひ使ってください。**Human-in-the-loop** から **Human-out-of-the-Loop** になるといいですね。ちなみにフォルダのダウンロードはファイルを再帰的にダウンロードするしか内容です。時間があったら実装します。ファイルのIDは28文字でフォルダのIDは33文字であってました？

# 参考
> [curlやwgetで公開済みGoogle Driveデータをダウンロードする](https://qiita.com/namakemono/items/c963e75e0af3f7eed732)
> [Google Driveから共有ファイルをダウンロードする](https://qiita.com/tanaike/items/688c9f981deb44f9e466)
> [GoogleDriveからcurlでダウンロードする](https://qiita.com/netwing/items/f2a595389f39206235e8)

# 追記1
フォルダもダウンロードできるようになりました。
保守のしやすいアプリケーションの初歩　マイクロサービスやDevOpsとともに

世の中ではここ数年、DockerとかDevOpsとか言われていたけれど、正直なところ色々なページを読んでもいまいちよく理解できなかった。そこで参考になりそうなところを読んでまとめることにした。

# キーワード１：疎結合

処理があっちゃこっちゃに飛びまくると人間の力ではそれを追うことができなくなり、結果的にスパゲッティなプログラムが出来上がる。多少実行速度を犠牲にしても、「互いに干渉し合わない独立したロジック」を個別に用意することで人間が把握しやすいコードとなり、保守性への近道になる。このコンセプトが「疎結合」と呼ばれる。

## 過去の対策例

以下、順不同：

+ 構造化プログラミング
+ オブジェクト指向・サービス指向
+ UNIXの思想

## マイクロサービス

疎結合の解として、現状のWeb系アプリケーションで最適なものは「[マイクロサービス](https://martinfowler.com/articles/microservices.html)」と呼ばれる。基本コンセプトとしては、特定のサービスを「よりシンプルなビジネスロジックを実装した小さなサービス」のまとまりとして実装すること。

例示が難しいのがいちばんのネックなのだけれど、[IBM DeveloperWorks 「マイクロサービス入門」](https://www.ibm.com/developerworks/jp/cloud/library/cl-bluemix-microservices-in-action-part-1-trs/index.html)では飛行機の予約システムを例にとって、下のような画像を掲載していた（これが最適な例なのかと言われると微妙なところだが）：

![飛行機の予約システムをマイクロサービスとして実装する](https://www.ibm.com/developerworks/jp/cloud/library/cl-bluemix-microservices-in-action-part-1-trs/microservices_101.png)

典型的な実装では、マイクロサービス同士はRESTのような静的プロトコルを用いてやりとりをする。注意すべきなのは、データベースのようなものもマイクロサービスごとに建てられているということ。マイクロサービス同士が共有しているのはHTTPの通信インフラのみ、ということになる。

このようにすることで、「コンポーネントごとの開発・保守」がより容易になる。汎用性の高いマイクロサービスは再利用されることも多いようだ。

# キーワード２：テスト

最初から完璧なアプリケーションは存在しない。できるだけ人柱の数を抑えてアプリケーションの不備を検出するには、動作テストを繰り返すしかない。

## テストで重要なコンセプト

今までの歴史でとくに重要なコンセプトは、以下の3つ（順不同）：

+ 単体テスト、結合テスト
+ テスト自動化
+ テスト駆動開発(TDD)

どのコンセプトも、根底にあるのは「コンポーネントの振る舞い」に焦点を絞っている点。「こういう入力を与えたら、こう動作して、このような出力を返すはず」という仕様をできるだけ明示的に記述する。そしてこのようなテストケースを、必要なだけ用意する。

仕様を明示的にすればするほどテストの自動化が容易になるし、どのように実装すれば良いかの方針が定まりやすくなる。このような利点を主張して、「実装を書く前にまずテストコードを書け」と薦めるのがテスト駆動開発である。

## 継続的インテグレーション

テストの自動化をつきつめると、不具合をできるだけ早期に検出するために「主要なテストはできるだけ頻繁に行った方がよい」という話になる。もちろんビルドすらしない場合もあるので、注意が必要。以前は「自分のサーバ上で定期的にテストコードを走らせる」というやりかたが主体だったけれど（「[デイリービルドは君の友達](http://japanese.joelonsoftware.com/Articles/DailyBuildsAreYourFriend.html)」）、最近ではコードベースに変更を加えるたび（特定のタグ付きのときだけ、でもよい）にビルドおよびテストを自動で行う、というやり方が多い。これが継続的インテグレーション(CI)と呼ばれる。

継続的インテグレーションを導入するには、概ね以下のようなことをする：

1. コードベースへの変更を検知できるようにする（GitだったらGit hook）
2. 変更イベントの際にすることを、レシピとして記述する

代表的なアプリケーションとしては、GitHubのサービスとしては[Travis CI](https://travis-ci.org/)が、そうでなければ[Jenkins](https://jenkins.io/)がある。

## DevOps

継続的インテグレーションの運用方法を核として、開発側と運用側のコミュニケーションあるいは意識の齟齬をできるだけ減らすよう考えられたのがDevOpsという概念である。DevOpsは考え方・意識の部分と技術的な部分からなるけれど、技術的な部分としては以下のような点が挙げられる（[Build Insiderの記事 「DevOpsとは何か？」](https://www.buildinsider.net/enterprise/devops/01)を参照）：

+ 環境構築の自動化：開発環境、テスト環境、運用環境を共通のレシピで構築できるようにすることで、環境の違いに起因する問題を早期に検出する
+ バージョン・バグ管理システムを一元化する：いつ何が更新されたのかだけでなく、個々の更新によって、どのバグにどのくらいのスピードでどこまで対応できたのかをわかりやすくする
+ 運用情報の共有：アプリケーションのサーバへの負荷などを逐一把握することで、動作障害を実装の改善につなげやすくする

結局のところユーザ人柱の発生は避けられない。DevOpsでは、いかにその被害を少なくして顧客満足度を上げるかという点に注意を向けている。

# これから

ほんとうは、上の文脈のなかでのDockerというものの位置づけについて考えたいのだけれど、おそらくそれを語るには仮想化についてもっと理解を深める必要がある気がする。なので、この記事はあと1年くらいは放っておかれることだろう。
react-ga の pageview をページ遷移毎に発火する with react-router v4

# まえがき
react-ga の issues に載ってた [history.listen を使う方法](https://github.com/react-ga/react-ga/issues/122#issue-222128136) も試したけど、多めに発火したり欲しいタイミングで発火しなかったりしちゃってやめた。

# 気持ち
- ページ遷移毎に pageview を発火したい
- いちばんはじめにサイトを開いた瞬間にも発火したい
- Routes の設定は別ファイルに書きたい
- Routes.js には GA のことは書かずに関係を疎にしておきたい

# 方法

```jsx:App.js
import React, { Component } from "react";
import { BrowserRouter } from "react-router-dom";
import ReactGA from "react-ga";
import routesGetter from "./Routes";
import { getGaId } from "./utils";

const Analitics = props => {
  ReactGA.pageview(
    props.location.pathname + props.location.search + props.location.hash
  );
  return null;
};

const Routes = routesGetter({ children: Analitics });

class App extends Component {
  constructor() {
    super();

    ReactGA.initialize(getGaId(), { debug: process.env.ENV === "dev" });
  }

  render() {
    return (
      <BrowserRouter>
        <Routes />
      </BrowserRouter>
    );
  }
}

export default App;
```

```jsx:Routes.js
import React, { Fragment } from "react";
import { withRouter, Switch, Route } from "react-router-dom";
import PageA from "./PageA";
import PageB from "./PageB";

const routesGetter = ({ children: Children }) => {
  return withRouter(routesProps => {
    return (
      <Fragment>
        <Children {...routesProps} />
        <Switch>
          <Route
            exact
            path="/pages/a"
            render={props => <PageA {...routesProps} {...props} />}
          />
          <Route
            exact
            path="/pages/b"
            render={props => <PageB {...routesProps} {...props} />}
          />
        </Switch>
      </Fragment>
    );
  });
};

export default routesGetter;
```
意図したとおりに動いた。ページを戻っても進んでも発火する。

# あとがき
もっといい感じに実装できればコメントください！
https://gist.github.com/moriyuu/0a4a46dbb0f002434ab1a43c97be31bc
Go言語　関数

#関数を定義
Go言語の関数の定義はfuncを使用します。

```go
package main
import "fmt"

func main() {
    fmt.Println(add(1, 2))
}

func add(a int, b int) int {
    return a + b
}
```

引数や戻り値も、変数と同じく型名が後につきます。
これは少し混乱しちゃいますね。。。

もちろん可変長引数も定義できます。

```go
func addAll(items... int) int {
    sum := 0
    for _, item := range items {
        sum += item
    }
    return sum;
}
```

なんと戻り値は複数返却できます！

```go
func main() {
    add, sub := addOrSub(10, 15)
    fmt.Printf("%d, %d", add, sub)
}

func addOrSub(a int, b int) (int, int) {
    return a + b, b - a
}
```

#関数のスコープ
名前が小文字から始まる場合、他パッケージから参照できないようです。

#関数のレシーバ
関数をtype型で宣言した型に関連づけることができます。

```go
package main

import "fmt"

// 身長と体重
type Status struct {
    height float32
    weight float32
}

// BIMを表示
func (s Status) getBMI() {
    fmt.Printf("BMIは%.1fです。", s.weight / (s.height * s.height))
}

func main() {
    var status Status
    // 身長と体重を入力
    status.height = 1.7
    status.weight = 70
    // BMIを表示
    status.getBMI()
    
}
```

実行結果

```
BMIは24.2です。
```
vuls v0.5.0 を使ってみた！！（環境構築編）

# vuls とは？

VULnerability Scanner の略で、Linux/FreeBSD向けの脆弱性スキャンツールです。

- [公式サイト](https://vuls.io/)
- [Github](https://github.com/future-architect/vuls/tree/master)
- [インストールガイド](https://vuls.io/docs/ja/install-manually-centos.html)
- [FutureVuls](https://vuls.biz/)

今回、**v0.5.0がリリース** されたため、やってみようと思います！

# 構成
以下の構成で実施します。

<img width="820" alt="アーキテクチャ.png" src="https://qiita-image-store.s3.amazonaws.com/0/212868/61a3657f-120d-72b4-3a76-21a570ad2d18.png">

# 準備
## [実行環境]
- AWS EC2（CentOS6 / scan target）
- AWS EC2（CentOS7.5 / vuls）

### AWS EC2（CentOS6 / スキャン対象）
1. 古いAMI（ami-25436924）からインスタンスを起動します。
2. セキュリティグループの設定
    - vuls サーバから[ssh(22)]でアクセス出来る設定
3. （今回は不要だけど）自動 yum update を抑止を行う
    - 以下をユーザデータへ記述する
    - [公式FAQより](https://aws.amazon.com/jp/amazon-linux-ami/faqs/)

    ```
    #cloud-config
    repo_upgrade: none
    ```

### AWS EC2（CentOS7.5 / vuls）
1. 外部へアクセス出来る（EIP保有 or NAT環境）インスタンスを起動します。
2. セキュリティグループの設定
    - スキャン対象サーバへ[ssh(22)]でアクセス出来る設定
    - NVDやJVNへでアクセス出来る設定
3. vuls インストールする
    - 下へ続く...

## [vuls インストール]
[手順](https://vuls.io/docs/ja/install-manually-centos.html)
### 1. vuls サーバへログインする
### 2. 各種インストールします
```
$ sudo yum -y install sqlite git gcc make wget
```
### 3. go を取得して、展開します
```
$ wget https://dl.google.com/go/go1.10.1.linux-amd64.tar.gz
$ sudo tar -C /usr/local -xzf go1.10.1.linux-amd64.tar.gz
$ mkdir $HOME/go
```
### 4. /etc/profile.d/goenv.sh を作成し、以下を記載します
```
$ vi /etc/profile.d/goenv.sh
```

```
$ export GOROOT=/usr/local/go
$ export GOPATH=$HOME/go
$ export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
```

### 5. 変数をセットします
```
$ source /etc/profile.d/goenv.sh
```

### 6. go-cve-dictionary 環境作成と取得

```
$ sudo mkdir /var/log/vuls
$ sudo chown centos /var/log/vuls
$ sudo chmod 700 /var/log/vuls
$ mkdir -p $GOPATH/src/github.com/kotakanbe
$ cd $GOPATH/src/github.com/kotakanbe
$ git clone https://github.com/kotakanbe/go-cve-dictionary.git
$ cd go-cve-dictionary
$ make install
```
```
$ cd $HOME
$ for i in `seq 2002 $(date +"%Y")`; do go-cve-dictionary fetchnvd -years $i; done
```

### 7. goval 環境作成と取得
```
$ mkdir -p $GOPATH/src/github.com/kotakanbe
$ cd $GOPATH/src/github.com/kotakanbe
$ git clone https://github.com/kotakanbe/goval-dictionary.git
$ cd goval-dictionary
$ make install
```

```
$ goval-dictionary fetch-redhat 6
```

### 8. gost 環境作成と情報取得
```
$ mkdir -p $GOPATH/src/github.com/knqyf263
$ cd $GOPATH/src/github.com/knqyf263
$ git clone https://github.com/knqyf263/gost.git
$ cd gost
$ make install
```

```
$ gost fetch redhat --after=2014-01-01
```

### 9. vuls インストール

```
$ mkdir -p $GOPATH/src/github.com/future-architect
$ cd $GOPATH/src/github.com/future-architect
$ git clone https://github.com/future-architect/vuls.git
$ cd vuls
$ make install
```

## [設定ファイル作成]
### 1. 作成

```
$ cd $HOME
$ vi config.toml
```

- 先ずはローカルを指す設定

```
[servers]
[servers.localhost]
host    = "localhost"
port    = "local"
```

### 2. 設定ファイル確認

```
$ vuls configtest
```

## [version 確認]
### 1. version 確認

```
$ vuls -v
vuls v0.5.0 44fa2c5
```

# まとめ

マニュアルを見ながら進めると大体スムーズに出来ました。
この後、新しい機能をやってみたいと思います！
(Java7以降限定)オブジェクトはObjects.equalsで比較してほしい

# Java 7より前の比較

オブジェクトを比較する際に、未だに下のようなコードを書いてしまう人（自社の人）がいる。
NullPointerExceptionを回避するために、定数から先に書いてみたり、

```java
if ("hoge".equals(hoge)) {
	// NullPointerExceptionになることはない
}
```

nullチェックを先にやってから、比較していたりする。

```java
if (hoge != null && hoge.equals("hoge")) {
	// hogeがNULLだった場合、後続のString.equalsは実行されない
}
```

# Java7以降の比較

Java 7以降を使っているならば、ぜひ```java.util.Objects.equals(Object a, Object b)```を使ってほしい。
これの場合、nullを考慮した比較を行ってくれる。

```java
if (Objects.equals(hoge, "hoge")) {
	// 処理
}
```

オブジェクトのポインタ(メモリ上の番地)が違っていても、
ちゃんと格納されている値同士で比較してくれるので安心。

```java
String hoge1 = "hoge";
String hoge2 = new String("hoge");

System.out.println(hoge1 == hoge2);               // false
System.out.println(hoge1.equals(hoge2));          // true
System.out.println(Objects.equals(hoge1, hoge2)); // true
```

# おまけ

この記事を書くにあたり、 java.util.Objectsについて、改めて調べてみました。
これは知らなかった！というものを書いてみます。

### toString

String型に変換するメソッド。
変換対象がnullだった場合、nullという文字列に変換される。

```java
Object obj = null;
String str = Objects.toString(obj);
System.out.println(Objects.equals(str, "null")); // true
System.out.println(Objects.equals(str, null));   // false 
```

null回避できるのは非常に良いことだが、nullという文字列に変換されるのは困る場面があると思う。
そんなときは、第2引数に文字列を設定すると、nullの場合に返す値を変更することができる。

```java
Object obj = null;
String str = Objects.toString(obj, "NULLです！");
System.out.println(str); // 出力結果：NULLです！
```

toStringメソッドは知っていたが、第2引数を設定できることを知らなかった。

### isNull／nonNull

isNullは引数がNULLの場合、 trueを返すメソッド。
nonNullは引数がNULLの場合、falseを返すメソッド。

```java
Object obj = null;
System.out.println(Objects.isNull(obj));  // true
System.out.println(Objects.nonNull(obj)); // false
```
```obj == null```よりは、スタイリッシュに見えます。
（```obj == null```や```obj != null```の挙動の違いは分かりませんでした…）

### requireNonNull

対象がNULLかどうかチェックするメソッド。
NULLだった場合は、NullPointerExceptionが発生する。

```java
Object obj2 = Objects.requireNonNull(obj1);
```
このメソッドを使わないでNULLチェックを行おうとすると、

```java
if (obj1 == null) {
	throw new NullPointerException();
} else {
	Object obj2 = Objects.requireNonNull(obj1);
}
```

となる。
地味な便利メソッドだと思う。


# 参考文献
[Objects (Java Platform SE 7)](https://docs.oracle.com/javase/jp/7/api/java/util/Objects.html)
[今までの書き方はもう古い！？ java.util.Objectsが便利すぎる](https://amg-solution.jp/blog/11164)
静的なサイトをherokuで爆速リリースしてBASIC認証をかける

# はじめに

GitHubPagesやNetlifyでリリースしてきましたが、今回はherokuで静的なサイトをリリースしてみます。

herokuになった経緯はBASIC認証をかけたかったんですが、GitHubPagesにはなく、Netlifyには有料プランでBASIC認証の代わりにパスワードをかけられるっぽく、ちょうどいいのがなくherokuにたどり着きました。

# 前手順

herokuアプリは作っておきます

```
brew install heroku/brew/heroku
heroku login
heroku create
```


# herokuで静的サイトをリリース

ここで言う静的サイトは、html,css,jsで構成されるサイトです。

herokuで静的なサイトをリリースするには、herokuにphpアプリケーションとして認識させる必要があります。

### index.php

```php
<?php
   header('Location: /index.html');
?>
```

### composer.json

```json
{}
```

### index.html

適当に

### ディレクトリ構成

![スクリーンショット 2018-08-29 0.53.18.png](https://qiita-image-store.s3.amazonaws.com/0/81308/d81e35c0-ff97-cfdf-21a2-292bc0280aca.png)

srcディレクトリはcss,jsが入ってます

## リリース

`git push heroku master`


# BASIC認証をかける

### .htaccess

```
AuthUserFile /app/.htpasswd
AuthType Basic
AuthName "Restricted Access"
Require valid-user
```

### .htpasswd

BASIC認証で利用するID/PASSWORDが記述されたファイル

下記サイトなどを利用して作成してください

[http://www.luft.co.jp/cgi/htpasswd.php](http://www.luft.co.jp/cgi/htpasswd.php)

### ディレクトリ構成

![スクリーンショット 2018-08-29 1.23.55.png](https://qiita-image-store.s3.amazonaws.com/0/81308/df5009f0-4c88-b421-4eee-b1f83248c58f.png)

## リリース

`git push heroku master`

# 終わりに

たぶん、最小構成だと思います。
Amazon EKS向けの「kubeconfig」設定ツールを作ってみた

# はじめに

Amazon EKSで作成したクラスタに対してkubectlコマンドで接続する際、kubeconfigファイル(~/.kube/config等)を記述する必要がありますが、[AWSの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/create-kubeconfig.html)に記載されている手順は以下のように手作業ベースとなっています。

1. AWS CLI (`aws eks describe-cluster`) を使用して、EKSクラスタの情報(エンドポイントURL、認証キー、等)を取得する。
2. 空のkubeconfigファイルを作成して、ドキュメントページに掲載されているテンプレートをコピペする。
3. テンプレート中のプレースホルダー(例：\<endpoint-url\>)を「手順1.」で取得した情報に置き換える。

EKSクラスタの作成を何度も行うような場合[^1]、これは結構な手間になります。

一方、Azure Kubernetes Service (AKS)では、Azure CLIの `az aks get-credentials` コマンドを一発叩くだけでkubeconfigファイルの設定が行えます。

EKSでも同じようなコマンドがあったらなぁ～、と思ったので、Go言語＆AWS-SDKの勉強がてらに作ってみました。

コードはこちらを参照：
https://github.com/hideakiaoyagi/kubeconfig-eks

# 使い方

基本的なコマンド構文は以下の通りです。

```shell:
$ kubeconfig-eks --config <kubeconfigファイルのパス> --name <クラスタ名> --region <リージョン>
```

`--config` オプションの省略時は `~/.kube/config` を参照します。
`--name` および `--region` オプションは省略できません。[^2]

また、kubeconfigファイル中にEKSクラスタ情報を書き込む際、各データの「name」キーは以下のような名前で設定されます。

```yaml:
clusters:
  name: eks-cluster
  cluster: ...

users:
  name: eks-user
  user: ...

contexts:
  name: eks-cluster
  context: ...
```

これらの値を変更したい場合は、それぞれ `--config-key-cluster`、`--config-key-user`、`--config-key-context` で指定します。


# コード解説

## main.go

コマンドラインツール作成支援ライブラリである `urfave/cli` パッケージを使用しました。
https://github.com/urfave/cli

`urfave/cli` は今風(？)の「`コマンド サブコマンド --引数`」形式のCLIも作成できる高機能なパッケージなのですが、今回は単純な「`コマンド --引数`」の作りにしました。
(Azure CLIのコマンド風に `kubeconfig-eks get-credentials --name...` とかにしても良かったのですが、無駄に長くなるので止めました)


## sub-aws-eks.go： AWS-SDKを使用したEKSクラスタ情報取得

情報取得には、AWS SDK for Goの関数 `DescribeCluster()` を使用します。
https://docs.aws.amazon.com/sdk-for-go/api/service/eks/#EKS.DescribeCluster

この関数の使い方は、

* 抽出条件(今回の場合は「クラスタ名」のみ)を指定した構造体を食わせて
* 抽出結果を構造体で受け取る

というもので、特にハマる点はありませんでした。


## sub-yaml.go： kubeconfigファイルの読み書き (YAMLデータのハンドリング)

YAMLデータをハンドリングするために `gopkg.in/yaml.v2` パッケージを使用しました。
https://gopkg.in/yaml.v2
https://github.com/go-yaml/yaml/tree/v2

実は、この部分が今回の一番苦労したところでした。

`gopkg.in/yaml.v2` パッケージでYAMLデータを扱う際、データの持たせ方には2通りの方法があります。

* YAMLデータの構造に合わせて予め構造体を定義しておく
* 構造が定まっていないYAMLデータを格納するために、interface{}型の要素を持つMapの構造体を用いる

kubeconfigファイルのYAML構成は、EKS、AKS、GKE、minikube、etc.へ接続する場合で少しずつ異なっています。
どのYAML構成であっても読み書きできるよう、今回は後者を採用しました。

基本的に各データは **map[interface{}]interface{}** 型となりますが、第1階層にある「`clusters:`」「`users:`」「`contexts:`」は直下に配列データを持つため **[]interface{}** 型となります。(それらの配下は **map[interface{}]interface{}** 型となる)

・・・と文章で書いても非常に分かり辛いですね。

下記の記事などを参考にさせて頂きました。
https://qiita.com/yamasaki-masahide/items/d6e406c4c11d5870a1c6


# おわりに

Go言語のセオリー(プロジェクト構成、エラー処理、etc.)が全く分かっていないので全然イケてないコードだと思いますが、所詮「習作」なので大目に見て下さい。
「こうしたらいいよ」というコメントは大歓迎です！(笑)


[^1]: EKSはコントロールプレーン(マスターノード)を作った時点で課金が開始されます。かつ、コントロールプレーンには「停止」の概念が無いため、課金を止めるには「削除」するしか方法がありません。個人学習用途で費用を節約するためには、こまめに「作成」「削除」するしかないのです・・・

[^2]: 本当は、`--region` オプション省略時は `~/.aws/config` ファイルに記述された「デフォルトリージョン」を採用するようにしたかったのですが、何故か `session.NewSession()` 関数がデフォルトリージョンを反映してくれないので、このような仕様となっています。(むぅ・・・)
PHPUnitで「例外が投げられないことを期待する」というテストケースをどのように書くか

# こんな「困った」時の話
「異常時に例外を投げる、正常に完了したらvoidとなる」というようなメソッドがあるとします。
こんな時に、PHPUnitでどのように単体テストを書けばいいでしょうか？

PHPUnitでは、1つもassertionがないテストを「Risky」としてマークします。これは賢いのですが、しかし「返り値をとれないメソッド」=assertionを置けないテストケースについてRiskyになってしまうのが困る・・・と悩んでいました。

# 結論: `@doesNotPerformAssertions` を使えそう
テストケースのアノテーションに `@doesNotPerformAssertions` を入れると、「これはリスキーじゃないぞ」という事を示すことができそうです。

以下、「こうやって対処してきた」「これからは@doesNotPerformAssertionsを使いたいかも」という話をします。

# いろいろな書き方
例えば、「(内容をバリデーションして)引き渡されたデータに誤りがあれば例外を投げる、問題がなければ何もしない」というメソッド `denyIfInvalidData()` があったとします。

## 微妙い例①
例えば「`AssertTrue(true)`をして無理矢理やるなどしていました。

```php
public function testDenyIfInvalidDataValidData()
{
    $data = ['requiredKey' => true];
    $this->subject->denyIfInvalidData($validData);

    // ここまで到達したらOK
    $this->assertTrue(true);
}
```
気持ち悪いな〜〜という思いがあります。

## 微妙い例②
次に思いつくのが、「catchブロックに到達しなかったらOKでは」という発想です。 

```php
public function testDenyIfInvalidDataValidData()
{
    $data = ['requiredKey' => true];
    try {
        $this->subject->denyIfInvalidData($validData);
    } catch (\InvalidArgumentException $e) {
        $this->fail('問題ないデータなのに拒絶されている');
    } finally {
        $this->assertFalse(!isset($e), '例外が発生している');
    }
}
```
これで、「例外が生じていなければOK」という流れは作ることができました。  
しかしどうにも冗長だし、 _Test as documentation_ の観点から「簡潔さ」が実現できていないように思います。(「例外が生じていないこと」に、なぜアサーションを2つも書かなければ行けないのでしょう？)

## 微妙い例③ -> 悪い例
「返り値がない」ので、 `null` 扱いができますね・・・PHPerのみなさん・・・

```php
public function testDenyIfInvalidDataValidData()
{
    $data = ['requiredKey' => true];
    $this->assertNull(
        $this->subject->denyIfInvalidData($validData);
        '問題ないデータなのに拒絶されている'
    );
}
```
「動き上の問題はない」と思われるのですが、これはPHPStan・Phan・PhpStorm等のコードを解析ツールに掛けると警告されるやり方です。そのくらい「悪い」と言えるでしょう。

PHPStan: Result of function __method__ (void) is used.
Phan: PhanTypeVoidAssignment
PhpStorm: 'void' method __METHOD__ result used.

## これでいいのでないか、という例
`@doesNotPerformAssertions` を利用すると、こうなります

```php
/**
 * @doesNotPerformAssertions
 */
public function testDenyIfInvalidDataValidData()
{
    $data = ['requiredKey' => true];
    $this->subject->denyIfInvalidData($validData);
}
````

記述量的にももちろん冗長さがないし、これなら「何を言いたいのか」というのがちゃんと際立つのではないでしょうか。
実行結果は `OK (1 test, 0 assertions)` となり、問題なくグリーンとなります。
もしこのアノテーションを付けていなかった場合、 `OK, but incomplete, skipped, or risky tests!sky tests!` となりグリーンとはなりません。

# `@doesNotPerformAssertions` とは何なのか
それでは、コイツは一体何者なのでしょうか？
今回話題に上げている内容の正にそのままなのですが、「テストケースがRiskyとして扱われる事を回避する」ためのものです。
https://phpunit.readthedocs.io/ja/latest/annotations.html?highlight=doesNotPerformAssertions#doesnotperformassertions
ズバリですね。「リスキーとみなさない」という表現は何とも消極的な気はしますが、「異常が無いことを保証する」という点で単体テストの本義は十分に果たせると思いますし、またSUTの実行も勿論走るのでカバレッジにも寄与することと思います。

## 関連するIssue
長らくPHPUnitに触れてきたのに今まで何で気づいてなかったん・・？という感はあるのですが、私がこの「ヒント」に辿り着けたのは以下の議論を発見できたからでした。
https://github.com/sebastianbergmann/phpunit-documentation/issues/171

## おわり

そもそも「単体テストをする」という意味で言えば「返り値を見る」という方がシンプルそうだし、そのように予め設計する〜というのも1つの考え方なのかもしれません。
とはいえreturn voidが「絶対に利用すべきでない」というものでもないはずですし、プロダクトコードにせよテストコードにせよ「筆者の気持ちがわかる」ような記述を心懸けながらパワフルで意義深いコードを書いていければ良いかな〜と思いました。
SRILM1.7.2を使ってみる

# インストールまでの手順
## ダウンロード
http://www.speech.sri.com/projects/srilm/download.html
## ディレクトリの作成
```
$ mkdir srilm
$ mv srilm-1.7.2.tar.gz srilm/
$ cd srilm
```
## 解凍
```
$ tar -zxvf srilm-1.7.2.tar.gz
```
上記コマンドを入力すると下記のエラーが起こるときがある。
`tar: Error exit delayed from previous errors.`
その場合はMac標準のアーカイブユーティリティーを使って解凍する。

## max-entropyモデルを作る場合

liblbfgsのインストール

```
$ curl -O https://github.com/chokkan/liblbfgs/archive/master.zip
$ unzip master.zip
$ cd master
$ ./autogen.sh
$ ./configure --enable-sse2
$ make
$ make install
```

SRILMの設定に追加 (macの場合)

```
$ echo HAVE_LIBLBFGS=1 >> common/Makefile.machine.macosx
```

## コンパイル
```
$ make SRILM=$PWD
```

# 使ってみる
5-gramの言語モデルを作ってみる

```
$ ./ngram-count -order 5 -text ~/data/train.txt -lm 5gram.txt
```

パープレキシティをはかる

```
$ ./ngram -lm 5gram.txt -ppl ~/data/test.txt
```
Kneser Neyスムージングで5-gram言語モデルを作ってみる

```
$ ./ngram-count -order 5 -kndiscount -kndiscount5 -kn-counts-modified -text ~/data/train.txt -lm kn.txt
```

Maximum entropy 言語モデルを枝刈りしつつ作ってみる

```
$ ./ngram-count -maxent -prune 1e-7 -text ~/data/train.txt -lm maxent.txt
```