OmniAICreator/Qiita-1.07M huggingface dataset:
ロードバランサー配下はHTTP通信する、HTTPSのテスト

このような、ロードバランサー配下環境は、HTTPで通信するHTTPS通信のテスト環境をローカルに用意したいが、テスト用のLoad Balancerが購入できません。代わりにWindowsのIISとARRとURL Rewriteツールでそれっぽい環境を作った話です。

[作りたい環境]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/adbcbd68-38cf-4c9e-e9d0-648243eec6a9.png)

[それっぽい環境]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/277b1d7e-d0a9-1e16-5292-3928e70344c1.png)

1. 役割と追加で、Ｗｅｂサーバ(IIS)をインストール

2. ARR3.0をインストール
https://www.microsoft.com/en-us/download/details.aspx?id=47333

3. ARRでEnable Proxy
    1. 「Application Request Routing Cache」をクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/8a244a59-28cc-f4c6-4ec9-0e4e3efe64ca.png)

    2.「Server Proxy Settings」をクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/cd059cb9-1c0d-199b-9d9c-2a9b06a43ebc.png)
 
    3.「Enable Proxy」にチェックを入れ、適用する
 
4. 「IIS URL Rewrite Module」をインストール
https://www.microsoft.com/ja-jp/download/details.aspx?id=7435&751be11f-ede8-5a0c-058c-2ee190a24fa6=True
 
5. 新しいServer Farmsを作成
    1.Server Farmsを右クリックし「Create Server Farms」を選択

    2.新しいServer Famrsの名前を入力
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/3a6bd9ee-23dd-12e7-7084-b64ef039cb2f.png)
 
    3.転送したいサーバ(HTTPでリクエストを送りたいサーバ）を指定
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/a2f75e43-1b23-db7e-251a-9042e2c6b946.png)

    4.作成したserverfarmを選択し、「Routing Rules」選択
 ![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/f63c3132-eec4-1ac8-a891-5ff6e43ced55.png)

 
    5.「Enable SSL offloading」にチェックが入っていることを確認
![image.png](https://qiita-image-store.s3.amazonaws.com/0/285371/41422ea9-9d9d-caea-265a-4cd5a439800b.png)

 
6. 自己証明書を作成
こちらのサイトを参考に、自己証明書をサーバに登録し、テストするクライアントにインポート
http://orochi8.blog.shinobi.jp/asp.net/iis7%E3%81%A7%E3%81%AE%E8%A8%BC%E6%98%8E%E6%9B%B8%E4%BD%9C%E6%88%90
 
7. Default Web Siteのバインドに、HTTPSを追加。証明書は、6で作成した証明書を使う
 
- 参考サイト  
HTTP Load Balancing using Application Request Routing  
https://docs.microsoft.com/en-us/iis/extensions/configuring-application-request-routing-arr/http-load-balancing-using-application-request-routing
gitで開発に関わった人の一覧を表示する方法

[mikutter 3.6.0 - mikutter blog](https://mikutter.hatenablog.com/entry/2017/12/25/012351)の謝辞の部分のコマンドがきれいだと感じたので、紹介します。

# コマンド
[mikutter](http://mikutter.hachune.net/) 3.6.0の開発に関わった人の一覧を表示する場合、以下のようになります。

```bash
$ git log --format="%an" 3.5.0..3.6.0 | sort | uniq
Akito Miura
Osamu Koga
Toshiaki Asai
ahiru
moguno
petitsurume
あひる 家鴨
```

前のリリース (3.5.0) から今回のリリース (3.6.0) までの間のコミットのAuthorを出し、そこから重複を除いているわけですが、コマンド一つで開発に関わった人の一覧をソートされた状態で出せるのがポイントではないかと思います。

# 参考文献
* [git logのフォーマットを指定する - Qiita](https://qiita.com/harukasan/items/9149542584385e8dea75)
[ruby]1.to_s +"hoge"と1.to_s + "hoge"の違い。スペースの有無が問題になる理由

## 伝えたいこと
特に理由がない限り、演算子の前後でスペースは空けようね

## 経緯
こういう書き方をするとエラーになると聞いた

```ruby
puts 1.to_s +"hoge"
```

## 再現を試みる

```bash
$ irb
irb(main):001:0> 1.to_s +"hoge"
TypeError: no implicit conversion of String into Integer
	from (irb):1:in `to_s'
	from (irb):1
	from /usr/local/bin/irb:11:in `<main>'
irb(main):002:0> 1.to_s + "hoge"
=> "1hoge"
```

確かに。

## 理由を調べた結果
以下の理由が要因となって、加算という演算子の扱いにならないようです。

* rubyはメソッド呼び出し時の（）を省略できる
* 数値.to_sは引数として数値を期待する
 * https://docs.ruby-lang.org/ja/latest/method/Integer/i/inspect.html

可読性もありますが、思わぬバグにつながることもありそうなので、
スペースはちゃんと空けたほうがいいなと思いました :innocent:
助けてください！pythonでサーバーが立ち上がらない

pythonを始めようと思い環境構築をしております。
Webサーバを起動しようと思い画像のようにコマンドを打ったのですがsyntax errorが
出てしまいます。
![スクリーンショット (1).png](https://qiita-image-store.s3.amazonaws.com/0/290841/f3f8b017-d99d-6118-7afe-fb7b03a0ea90.png)

他のテキストエディタなどでも試してみましたが効果がなかったです。
![スクリーンショット (2).png](https://qiita-image-store.s3.amazonaws.com/0/290841/2b1ec8b5-6165-042a-a090-a8ed00927104.png)


構文は間違っていると思わないのですがどうしてもここからすすめません。
助けてください。
php-master-changes 2018-09-13

今日も Dmitry が元気め
エラー処理は積極的に関数へ切り出して cold へ回した方が、分岐予測のヒントになったり、エラー処理のコードがキャッシュ圧迫しないようなバイナリレイアウトにできたり、という感じか

# 2018-09-13
## dstogov: Optimize method/property visibility checks
- https://github.com/php/php-src/commit/5293dd9d8b263007b3c6f1c3a1c98915156f7d28
- メソッド/プロパティの可視性チェック処理を最適化

## weltling: Add debug message for failing test parts
- https://github.com/php/php-src/commit/a45169a6ba54b13484d70cb474679c96347f779b
- ext/openssl のテストでエラー処理箇所へデバッグメッセージを追加

## weltling: Show all unmatched errors when test failed
- https://github.com/php/php-src/commit/70159652541c62b5f3bbb26da76b7e56987b2544
- ext/openssl のテストでエラー処理箇所へデバッグメッセージをもっと追加

## dstogov: Avoid unnecesury iterations over parent classes, in case of no overriden private properties.
- https://github.com/php/php-src/commit/cdeebfd4afd270a7628344b544356f3d15c50372
- プロパティへのアクセス用配列を内部で構築する際、オーバライドした private プロパティがない場合には、祖先のプロパティテーブルをたどってデータを引っ張る処理を省くよう最適化

## dstogov: Micro-optimization
- https://github.com/php/php-src/commit/f79270d8764ac6b1c34e5697a93d204a7a460d29
- 分岐予測ヒントを足したり分岐の処理順を変えたり、2 つのクラスが protected でアクセスできる関係にあるかのチェック用関数を変えたりの最適化

## weltling: More possibly colliding libs to remove from the test image
- https://github.com/php/php-src/commit/3008ad1a49210e4604522a987cbdd27a5a0a2c42
- AppVeyor でのテストイメージから衝突するかもしれない？ライブラリを削除
- OpenSSL〜 のディレクトリを外してるっぽいけど、よく分かっておらず

## dstogov: typo
- https://github.com/php/php-src/commit/eb4148e02dbff5b52016a5d583c690ffcbe46cad
- typo の修正

## dstogov: Micro-optimization (condition reordering)
- https://github.com/php/php-src/commit/e1ef054be5b9cbba6281d6168150ca98ad6bdc53
- 分岐の並べ替えによる最適化

## dstogov: Split error code into "cold" functions and cleanup.
- https://github.com/php/php-src/commit/a12cd1c5e0a85850a923ca0efb1752b2be69e552
- エラー処理を ZEND_COLD な関数へ切り出し
- サポートされている環境では \__attribute__((cold)) に展開され、そんなに使われない関数としてコンパイラに特別扱いさせられる

## weltling: Remove colliding file from CI image
- https://github.com/php/php-src/commit/6220d21c3420ff0d7366d410920ba5279fba3893
- AppVeyor のイメージから衝突するファイルを削除

## weltling: Fix typo
- https://github.com/php/php-src/commit/24517d82cf8dc708d08bc77435ad418de4bdff4e
- typo の修正

## dstogov: Make visibilty check in is_callable() to be consistent with zend_std_get_method()
- https://github.com/php/php-src/commit/72bf2def6b718ae9ca243b6a9ab9a3a85d255f96
- is_callable() の可視性チェック処理を zend_std_get_method() と一貫性あるものに修正

## TysonAndre: Fix a typo in a class catch in Phar
- https://github.com/php/php-src/commit/26f952b1759ffd81965913b3440753c1356487f6
- ext/phar の phar コマンドのコードにあった typo を修正

## dstogov: Simplify __clone() visibility check (magic methods still don't respect ZEND_ACC_CHANGED).
- https://github.com/php/php-src/commit/bc288c47230919c326b82133ff5306f4eff690b4
- __clone() の可視性チェック処理を単純化

## dstogov: Remove zend_check_private()
- https://github.com/php/php-src/commit/49b92446d780bcb750d65148bc4ad1519bf66fb3
- zend_check_private() の削除
- 今後は (func->common.scope == scope) を使うよう UPGRADING.INTERNALS へ追記
実際Nuxt.jsとExpressでどうやってSSRやるか理解してましたか？自分はよくわかってなかったです【解説】

最近は、

* Firebase Cloud Functions（Node v8）：バックエンド処理
* Nuxt.js：JSフレームワーク
* Firebase Hosting：css, jsファイルなど静的ファイル
* Cloudinary：画像等メディアファイル

が爆速でWebアプリケーションを開発する最適解だと考えているのですがどうでしょう？

自分が最初Firebase x Nuxt.jsで開発を始めた際、なかなか理解できなかったのが、
Nuxt.jsとExpressがどう繋がっているのかということでした。
Express(Firebase Cloud Functions)で受けて、どうやってNuxt.jsと連携するの？ という疑問がなかなか晴れず。  
そこで今回は、自分で作ったFirebase x Firebase用vueテンプレートを混ぜ込みつつ解説したいと思います。

## ExpressとNuxt.jsの連携

### ポイント1. Nuxt.jsはExpressの中でミドルウェア的に使う
Nuxt.jsはExpressの中で、1つのmoduleとして使用します。　　
例）https://github.com/taishikato/nuxt-express-firebase-template/blob/master/template/functions/index.js#L2  
いままでVue.jsなどでSPAを作るのに慣れていると、フレームワークをモジュールとして使うという発想はなかったかなと思います（自分はなかった）。
この考え方の切替が結構大事かなと思います。

### ポイント2. [nuxt.renderRoute()](https://ja.nuxtjs.org/api/nuxt-render-route/)でパス毎に処理を分ける

[このように書く](https://github.com/taishikato/nuxt-express-firebase-template/blob/master/template/functions/index.js#L17-L29)ことでパス毎に、Nuxt.jsのどのPage Componentを出力するか、決定できます。　　
ポイントは`nuxt.renderRoute()`メソッドを使うことです。
`nuxt.renderRoute()`について、[公式ドキュメント](https://ja.nuxtjs.org/api/nuxt-render-route/)には以下のように書いています。
> 特定のルートをレンダリングします。その際にコンテキストを渡すことができます。

仮に、アプリケーションのURLをhttps://example.com とすると、
例えば以下のように書いた場合、https://example.com にアクセスしたら、Nuxt.jsの`pages/top.vue`が使用されます。簡単ですね。

```javascript
app.get('/', (req, res) => {
  nuxt.renderRoute('/top', { req })
  .then(result => {
    res.send(result.html);
  })
  .catch(e => {
    res.send(e);
  });
});
```

また、第二引数にコンテキストを渡すことができます。
> オプション, オブジェクト, 付与するコンテキスト, 利用できるキー: req 及び res

上記の例で、仮にExpressでAPIを実行し、得た情報をNuxt.jsで描画したい場合、以下のように、`req`オブジェクトに入れてあげると、

```javascript
app.get('/', (req, res) => {
  (async () => {
    // axiosでAPIを実行します
    const { data } = await axios.get('https://api.com');
    req.data = data;
    const result = await nuxt.renderRoute('/top', { req });
    res.send(result.html);
  })();
});
```
Nuxt.jsの`asyncData`メソッドで参照することができます

```html
<template>
  <div>
    {{ apiResult }}
  </div>
</template>

<script>
export default {
  asyncData(context) {
    return { apiResult: context.req.data };
  }
}
</script>
```

## 図で説明
1. Firebase Cloud Functionsへリクエスト、Expressが受け取ります
2. Expressの該当Router内で`nuxt.renderRoute()`を実行
3. Nuxt.jsがHTMLを生成して、Expressへ返却
4. Nuxt.jsから返されたHTMLをExpressがクライアントへsend

![Nuxt x Express.png](https://qiita-image-store.s3.amazonaws.com/0/18699/848e0b77-dd99-233b-3b29-8d813a1390ec.png)

## 宣伝

vueテンプレート
:fire: [taishikato/nuxt-express-firebase-template](https://github.com/taishikato/nuxt-express-firebase-template)
ぜひぜひ
絵で覚える正規表現 —「先読み」と「後読み」は「マッチ進行方向」が鍵

## 参考

>lookaheadは、現在地から進行方向にあるものを先取りして見ることです。/b(?=a)/の場合、「現在地」はbで、そこに立って進行方向にaがあるかを見るのでlookaheadと呼びます。

[[コラム] 正規表現の先読み/後読みは、どう考えても名前が悪いので、呼称禁止令を出してルックと気軽に呼んでみませんか。 - Qiita](https://qiita.com/mochizukikotaro/items/84f3ab2740b8efbe0dc6#comment-9073b5e77e0e237412fa)


## 昔とあるところに正規表現がいた

![image](https://user-images.githubusercontent.com/13635059/45459035-793b2580-b731-11e8-8633-4a698d4d34a8.png)

## マッチは左から右へと進む

![image](https://user-images.githubusercontent.com/13635059/45459040-7dffd980-b731-11e8-8206-ba059406b34d.png)

## 「先」とは「マッチの進行方向」に対して「先」だ

元は Lookahead (前方向を見る) という

![image](https://user-images.githubusercontent.com/13635059/45459041-7fc99d00-b731-11e8-9171-e11150133246.png)

## 「後」とは「マッチの進行方向」に対して「後ろ」だ

元は Lookbehind (後ろを振り返る) という

「あと」というより「うしろ」

「戻り読み」と訳しているサイトもある

![image](https://user-images.githubusercontent.com/13635059/45459042-81936080-b731-11e8-843e-061b3bd187af.png)

## マッチは始まりから終わりへと進む

未来に向かっているのが「先」で

過去を振り返るのが「うしろ」だ

![image](https://user-images.githubusercontent.com/13635059/45459053-8eb04f80-b731-11e8-8f5d-10d9bcdbf3bd.png)


## よく見ると「後読み」の記法には「過去」に向いた左矢印がある


![image](https://user-images.githubusercontent.com/13635059/45520778-e3b59980-b7f5-11e8-9ee6-823e6b3f6d08.png)


## 逆に「先読み」の記法には「未来」を向いた右矢印はない

だが時間が過去から未来へと進むのはあまりにも当たり前なので、省略されているのだ、と考えてみる。

![image](https://user-images.githubusercontent.com/13635059/45520759-d8fb0480-b7f5-11e8-888b-38e2da4f0cae.png)

## Links

- [絵で覚える正規表現 — 始まりは太陽、終わりは音楽。 - Qiita](https://qiita.com/YumaInaura/items/201c515d3379b5e72e8d)
- [Gist](https://gist.github.com/YumaInaura/da4c4451ca49faab83860377cc81ef98)
- [Medium—imported](https://medium.com/supersonic-generation/regex-how-to-remember-lookahead-and-lookbehind-bf2f47308753)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
leafletを鍛える。その５

#概要
leafletを鍛えてみた。
pixiを、使ってみた。

#写真

![](http://jsdo-static-contents.s3.amazonaws.com/images/capture/y/M/g/yMg7V.jpg?t=1536873716)

#サンプルコード

```
var map = L.map('map').setView([37.9, 140.1], 12);
var mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>';
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; ' + mapLink + ' Contributors',
    maxZoom: 18,
}).addTo(map);


var loader = new PIXI.loaders.Loader();
loader.add('marker', 'http://jsrun.it/assets/I/S/D/k/ISDkX.png');
loader.load(function(loader, resources) {
    var markerTexture = resources.marker.texture;
    var markerLatLng = [37.9, 140.1];
    var marker = new PIXI.Sprite(markerTexture);
    marker.anchor.set(0.5, 1);
    var pixiContainer = new PIXI.Container();
    pixiContainer.addChild(marker);
    var firstDraw = true;
    var prevZoom;
    var pixiOverlay = L.pixiOverlay(function(utils) {
        var zoom = utils.getMap().getZoom();
        var container = utils.getContainer();
        var renderer = utils.getRenderer();
        var project = utils.latLngToLayerPoint;
        var scale = utils.getScale();
        if (firstDraw)
        {
            var markerCoords = project(markerLatLng);
            marker.x = markerCoords.x;
            marker.y = markerCoords.y;
        }
        if (firstDraw || prevZoom !== zoom) 
        {
            marker.scale.set(1 / scale);
        }
        firstDraw = false;
        prevZoom = zoom;
        renderer.render(container);
    }, pixiContainer);
    pixiOverlay.addTo(map);
});
```

#成果物
http://jsdo.it/ohisama1/yMg7V


以上。
leafletを鍛える。その４

#概要
leafletを鍛えてみた。
canvasに、書いてみた。

#写真

![](http://jsdo-static-contents.s3.amazonaws.com/images/capture/c/3/c/c3cC.jpg?t=1536834252)

#サンプルコード

```
var map = L.map('map').setView([37.9, 140.1], 12);
var mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>';
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; ' + mapLink + ' Contributors',
    maxZoom: 18,
}).addTo(map);

L.canvasLayer().delegate(this).addTo(map);
      
function onDrawLayer(info) {
    var ctx = info.canvas.getContext('2d');
    ctx.clearRect(0, 0, info.canvas.width, info.canvas.height);
    ctx.fillStyle = "rgba(255, 116, 0, 255)";
    ctx.beginPath();
    ctx.arc(140, 140, 30, 0, Math.PI * 2);
    ctx.fill();
    ctx.closePath();
}
```

#成果物

https://embed.plnkr.co/iEwTDQcUwsPFKPTIN8ha/


以上。
leafletを鍛える。その3

#概要
leafletを鍛えてみた。
canvasに、書いてみた。

#写真

![](http://jsdo-static-contents.s3.amazonaws.com/images/capture/e/F/J/eFJu.jpg?t=1536827674)

#サンプルコード

```
var map = new L.Map('map', {
    center: [38, 140],
    zoom: 2
});
var tiles = new L.GridLayer();
tiles.createTile = function(coords) {
    var tile = L.DomUtil.create('canvas', 'leaflet-tile');
    var ctx = tile.getContext('2d');
    var size = this.getTileSize();
    tile.width = size.x;
    tile.height = size.y;
    var nwPoint = coords.scaleBy(size);
    var nw = map.unproject(nwPoint, coords.z);
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, size.x, 50);
    ctx.fillStyle = 'black';
    ctx.fillText('x: ' + coords.x + ', y: ' + coords.y + ', zoom: ' + coords.z, 20, 20);
    ctx.fillText('lat: ' + nw.lat + ', lon: ' + nw.lng, 20, 40);
    ctx.strokeStyle = 'red';
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(size.x - 1, 0);
    ctx.lineTo(size.x - 1, size.y - 1);
    ctx.lineTo(0, size.y - 1);
    ctx.closePath();
    ctx.stroke();
    return tile;
}
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
   attribution: 'Map data &copy; <a href="http://www.osm.org">OpenStreetMap</a>'
}).addTo(map)
tiles.addTo(map)

```

#成果物

https://embed.plnkr.co/4y5RBqLo9aAi6bpoUV8p/


以上。
URL集


9/19
Rails: データベースのパフォーマンスを損なう3つの書き方（翻訳）
https://techracho.bpsinc.jp/hachi8833/2018_01_11/50793


Railsでメール自動配信機能をつくるまでの道程
https://qiita.com/Yama-to/items/823baf26bba3193712ea


Rails 検索機能でよく使われる表現 あいまい検索
https://qiita.com/kinokosan/items/7a07bd2a307571c68335
【Rails入門】where likeであいまい検索！複数条件やOR条件も解説
https://www.sejuku.net/blog/71189

whereで複数条件検索
https://qiita.com/katsuyuki/items/20896fa26aa726499e3f

9/24

https://webnetamemo.com/coding/bootstrap4/201711116162
processmaker mysql から websock

#条件分岐（ルーティングの際にＭＹＳＱＬからＷＥＢＳＯＣＫを叩く）
 いろいろと問題は出ると思うが　専用のＷＥＢＳＯＣＫ用のＭＹＳＱＬサーバーであれば基幹システムには影響しない

#背景
 ＢＰＭＳは複数のシステムと連携するので　いろんなフロントのプログラムがあっても最終的にデータベースは通るので　その度にシステムレベルのプログラムにあわせるより　共通化したい為
##プログラムレベルだと色々な言語にあわせないといけないのでＭＹＳＱＬでＷＥＢＳＯＣＫをたたくように設定

###これであれば　ＭＹＳＱＬのシステムの物であれば既存の物にも対応できる

![bpmchat.JPG](https://qiita-image-store.s3.amazonaws.com/0/37985/437dbfa7-0e35-ac41-a487-a52e90019382.jpeg)
#チャットの内容でのルーティングのＷＥＢＳＯＣＫをいれチャットに送信
![websock.JPG](https://qiita-image-store.s3.amazonaws.com/0/37985/c377c733-7186-b9b3-f811-119783f39310.jpeg)



```sendWebSock.sql
BEGIN

set @word = casea;

set @cmd = concat('import websocket
if __name__ == "__main__":
        websocket.enableTrace(True)
        ws = websocket.create_connection("wss://***.***.***.***:9000")
        ws.send("',@word,'")
        result = ws.recv()
        print(result)
        ws.close()');
　 　　 select sys_eval(concat("python3 -c '",@cmd,"'>/dev/null 2>&1 ")) into @d;
	RETURN 0;
END
```
mac 環境構築あれこれ

mac初心者の様々な設定記録です。

# macOS sierra(10.12.6)
ハード:macbook air(13-inch mid 2013)
昔買ったものの、あまり使用せず眠ってたのを、最近活用しています。

## bootcamp〜win10インストール
ドラクエをしようと思い、windows10を購入して、bootcampを設定しました。
USBメモリにmicrosoftのサイトからisoイメージをコピーして、インストール。
やり方が悪かったのか、windows→macの切り替えでうまくいかず（bootディスクを選択するように起動しないといけなくなる)やり直し。インストールの過程で余計なことしたかも。
もともとSSDが128Gしかなく、win10にどれぐらい割り当てるべきか悩ましいところ。
とりあえず50Gをwin10に割り当て、office365やドラクエ入れたら、残りが5Gしかなくなった(涙目)。
ドラクエはswitchでやればいいし、そのうち消すかなぁ、、、、
ファイルはオンラインストレージに置くし、ローカルディスクは少なくてもいいでしょと思って128Gにしたのが間違いだったか。次はmacbook pro 512G買うと心に誓う。

## Anacondaのインストール
機械学習のためにanacondaを入れました。
どう入れたのか覚えてない^^; 

## Xcode 9.2
swiftをやってみようかと思って、Xcodeを入れようと思います。
macOSはもうすぐmojaveが出るようなので、OSをhigh sierraにしようかと思ったのだけど、high sierraはファイルシステムがAPFSになるとのこと。この時にbootcampが稼働しなくなるとかなんとかという記事を見て、とりあえずOSバージョンアップは据え置き。
そうすると、最新のXcodeは入れられず、sierraで動かせる9.2を入れることに。
インストールはあっさり。
【トラックパッド】BetterTouchToolsの個人的便利設定【ジェスチャ】

#はじめに
マカーの皆さん大好きBetterTouchToolです。現在有料ソフトですが、このソフトについては買うべきだと感じます。その中で、私がトラックパッドに対してジェスチャ設定の一部を載せたいと思います。

#環境
MacBook Pro (Retina, Mid 2012)
OS X El Capitan
BetterTouchTool Version: 2.626

#設定内容(Global)
<img width="1010" alt="スクリーンショット 2018-09-14 2.25.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/290735/6b00945f-380a-7cac-829e-82421753bc7c.png">

##リンククリック
トラックパッドにはミドルクリックに該当するものがないため、ミドルクリックっぽい動きを追加します。

|ジェスチャ名|実行コマンド|内容|
|---|---|---|
|TipTap Middle (2 Fingers Fix)|CMD(⌘)+Click|リンクをバックグラウンドの新しいタブで開く(Chrome)|
BetterTouchTool上ではこのような設定になります。
<img width="479" alt="スクリーンショット 2018-09-14 3.33.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/290735/cd16d53c-a94a-d045-a2c9-a6be100d4aa1.png">



##説明(4本指操作)
個人的に四本指の上下スワイプは使わないので、オフにしております
<img width="658" alt="スクリーンショット 2018-09-14 2.46.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/290735/fafd9a3f-a040-8d64-575d-7774905d6f96.png">

|ジェスチャ名|実行コマンド|内容|
|---|---|---|
|4 Finger Swipe Up|CMD(⌘) + W|四本指上スワイプでアプリを閉じる等|
|4 Finger Swipe Down|Enter Fullscreen (If Supported)|四本指下スワイプでフルスクリーン及び解除|

BetterTouchTool上ではこのような設定になります。
<img width="543" alt="スクリーンショット 2018-09-14 3.05.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/290735/60fe56f5-2241-de69-3178-72aba8296e22.png">


##説明(ウインドウ操作)
WindowsではWindowsロゴキー+上下左右でウインドウの位置を変更出来ますが、それをBetterTouchToolで行います。

|Modifiers|ジェスチャ名|実行内容|内容|
|---|---|---|---|
|CMD(⌘) CTRL(⌃)|1 Finger Tap Top Left|Resize Window to Top Left Quarter / Corner|CMDとCTRL押しながらトラックパッド左上タップで、ウインドウを左上へ
|CMD(⌘) CTRL(⌃)|1 Finger Tap Top Right|Resize Window to Top Right Quarter / Corner|CMDとCTRL押しながらトラックパッド右上タップで、ウインドウを右上へ
|CMD(⌘) CTRL(⌃)|1 Finger Tap Bottom Left|Resize Window to Bottom Left Quarter / Corner|CMDとCTRL押しながらトラックパッド左下タップで、ウインドウを左下へ
|CMD(⌘) CTRL(⌃)|1 Finger Tap Bottom Right|Resize Window to Bottom Right Quarter / Corner|CMDとCTRL押しながらトラックパッド右下タップで、ウインドウを右下へ
|CMD(⌘) CTRL(⌃)|1 Finger Tap Right Side Middle|Maximize Window Left|CMDとCTRL押しながらトラックパッド左端タップで、ウインドウを左半分へ
|CMD(⌘) CTRL(⌃)|1 Finger Tap Left Side Middle|Maximize Window Left|CMDとCTRL押しながらトラックパッド左端タップで、ウインドウを右半分へ
BetterTouchTool上ではこのような設定になります。
<img width="628" alt="スクリーンショット 2018-09-14 3.38.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/290735/922c58f9-227a-72d8-2b33-21d17ee6893e.png">

少ないですが設定の紹介については以上です。快適なBetterTouchToolライフを！
メモ：Tensorflowを自動微分用ツールとして使う．

# sess.run()
定番のやり方．

```python
import tensorflow as tf
X = tf.placeholder(tf.float32, shape=[None, 1], name="x")
Y = X**2
gradY =  tf.gradients(Y, [X])
init = tf.global_variables_initializer()
data = np.linspace(-2,2,100).reshape(-1,1)
sess = tf.Session()
sess.run(init)
ret = sess.run(gradY, feed_dict={X:data})
```

# tf.eager_execution()
sessionをいちいち実行するのはあまりイケていない感じもする．このような場合TensorFlowのEager Executionを使える．
https://www.tensorflow.org/api_docs/python/tf/GradientTape
勾配を計算したい場合，Gradient Tapeをつかって，fowardしたときの値を記録しておくようにしないといけない．

```
import numpy as np
import tensorflow as tf
import tensorflow.contrib.eager as tfe

tfe.enable_eager_execution()
x = tf.constant(np.linspace(-2,2,100))
with tf.GradientTape() as g:
  g.watch(x)
  y = x * x
dy_dx = g.gradient(y, x)

```
Dockerコンテナ実行時のリトライ処理

最近AWS ECS、Fargate、Batchとコンテナに囲まれた生活を送っていた。

そんな中で「コンテナプロセスのリトライ処理出来るBatch君すごい！AWS様すごい！」とか思ってて、仮に自前でリトライ処理やろうと思ったらどうやればいいんだろうとか思いながら、[Dockerドキュメント](http://docs.docker.jp/index.html)を読み漁ってたら**Docker run リファレンス**内に `restart` フラグを見つけて感動したので記事にした。

## tl;dr

- `docker container run` コマンド実行時に引数として `--restart=on-failure:xx` を渡すとリトライ処理が可能(xx=整数)
- リトライ処理の実行条件はコンテナプロセス終了コードが0以外の場合
- リトライされたコンテナプロセスはバックグラウンドプロセスで実行される

## 本当にリトライされるか検証

### 検証環境

- macOS 10.13.1, Darwin 17.2.0
- Docker version 18.06.1-ce


### ディレクトリ構成

いつも自分が作業するディレクトリの下に以下のディレクトリ構成を作成する。

ディレクトリ名: retry_container

```
retry_container
.
├── Dockerfile
└── date.log

0 directories, 2 files
```

#### 検証用Dockerfile

以下の内容を作成したDockerfile内に貼り付ける。

```Dockerfile
FROM alpine:3.8
CMD date >> /tmp/date.log && echo "container run!" && exit 1
```

このDockerfileで作成されるコンテナの振る舞いとしては以下の通り。

- `date`コマンドの標準出力を`/tmp/date.log`に書き込む
- `echo`コマンドでホストマシン側に実行されたと分かる文字列を出力
- `exit` コマンドに引数として`1`を渡し、プロセス終了コード`1`としてコンテナプロセスを終了させる

#### date.log

touchだけでOK。

```shell
$ touch date.log
```

### コンテナイメージを作成

`Dockerfile`と`date.log`が用意できたらビルドする。

```shell
$ docker build -t retry_container .
```

Successfully built というメッセージが流れたらビルド成功。

### コンテナを実行してみる

```shell
$ docker container run -v $HOME/work/retry_container/:/tmp/ retry_container:latest
```

-vオプションを用いて、ホストマシンの`$HOME/work/retry_container/`ディレクトリ以下の内容をコンテナ内の `/tmp/` ディレクトリ以下にマウントしている。

`$HOME/work/` 部分のファイルパスに関しては自分の環境に合わせて書き換える必要有り。

実行結果は以下の通り

```
container run!
```

```shell
$ cat ./date.log
Thu Sep 13 17:18:52 UTC 2018
```

ホストマシン側には標準出力として `echo` で出力した文字列と`date.log` ファイル内にはコンテナ内で実行した`date`コマンドのUTC時刻が書き込まれているはず。

書き込まれていれば、コンテナの実行は成功。

### `restart` フラグを付与してコンテナを実行してみる

```shell
$ docker container run --restart=on-failure:10 -v $HOME/work/retry_container/:/tmp/ retry_container:latest
```

`restart` フラグに与える引数は`on-failure:10`なのでリトライ処理試行回数は10回となる。

実行結果

```
container run!
```

出力を見た感じ`restart`フラグを付ける前と変わっていない感じがする。

しかし、`date.log`ファイルの中身が大きく変わってくるはずだ。

```shell
$ cat ./date.log
Thu Sep 13 17:18:52 UTC 2018
Thu Sep 13 17:35:35 UTC 2018
Thu Sep 13 17:35:37 UTC 2018
Thu Sep 13 17:35:38 UTC 2018
```

明らかに自分が実行した回数以上に`date.log`ファイルに`date`コマンドの出力が書き込まれているはず。

`docker container run --restart=on-failure:10 -v $HOME/work/retry_container:/tmp/ retry_container:latest`を実行して、数十秒の間に`docker container ls`コマンドを実行してみよう。

すると、現在実行されているコンテナとして`retry_container:latest`がまだ実行されているはず。

なぜ`date.log`は書き込まれているのに、`echo`がホストマシン側に出力されないかというと、リトライされたコンテナプロセスはバッググラウンドプロセスで実行されるからだ。

数分待ったあとに`docker container ls`を実行して、`retry_container:latest`コンテナが実行されていなければ10回分のリトライ処理が終了したということになる。

確認してみよう。

```shell
$ cat ./date.log | wc -l
12
```

書かれた手順通りに進めたなら`12`という数字が出力されるはず。

- コンテナが正しく実行されるかどうかの確認として1回
- リトライ処理に入る前に実行されたので1回
- リトライ処理として10回

`restart`フラグに引数として渡した値分リトライ処理されていることが分かった。

リトライインターバルに関しては不明。

時間があれば調べてみよう。。

リトライ処理される度にインターバルが長くなっている気はする。

## 所感

AWS Batchのリトライ処理に関しては`restart`フラグ使ってリトライ処理を実現してそう。

改めてリファレンスは時間のある時に目を通した方が良いなというのを強く感じた。
スライドショーを実装するjQueryプラグインやライブラリはどれを選べばよいのか。

#いつも同じプラグインを使い回せるとは限らない#
これはまで数えきれないほど多くのサイトで採用されてきた、スライドショー・写真ギャラリー。
自分で1からJavaScriptを書かなくても、数多く配布されているjQueryプラグインやライブラリを使えば簡単に実装できます。

1度プラグインを使ってスライドショーを作った経験があれば、次に別のサイト制作で必要になった時にも同じプラグインを使い回すことでより効率よく作業を進められると考えがちですが、実はそう簡単にいかないケースもあります。

##スライドショーといっても形は様々
一口にスライドショーといっても、いろいろなパターンが考えられるのがその理由です。

- レスポンシブに対応しているか
- スワイプに対応しているか
- スライドショーの画像サイズ・縦横比はバラバラでも対応できるか
- 画像ごとのキャプションは入れられるか
- サムネイルの有無
 - そのサムネイルはカルーセルになるかどうか
 - （さらに）画像が特定の枚数以上の時だけサムネイルをカルーセルにできるか（主にCMS対応）
- 縦向きのスライドショーにできるか
- スライドショーにパララックス効果をつけられるか  
- jQueryバージョンの問題 
- 画像の遅延読み込み（Lazy Load）はできるか

ざっと思いつくものを挙げてみただけでもこれだけ思い浮かびます。

## 1つのプラグインだけでどんなスライドショーも..とはいかない

もちろん、よく利用されているスライドショー用のjQueryプラグインにはオプションが豊富に用意されており、これらの要件を実現することも簡単です。

しかし1つのプラグインだけで、どんなスライドショーにも簡単に対応できるかというと、そうではなく「この要件とこの要件には合っているけど、これは実現できないのか..困った..」なんてことも起こりえます。

だからサイトのデザインやスライドショーの仕様が変われば、前のサイト制作で使ったスライドショー用のプラグインをそのままコピーして使うわけにはいかず、他のプラグインを探さなければならない、なんてことがあるのです。

特にやっかいなのはCMSに実装するときだなと感じています。
画像のトリミングなどできないお客さんが、スライドショーを自分で更新する場合です。
（デザインの要件に加えて、登録される画像のサイズ・縦横比バラバラかつ、何枚でもOKに対応したスライドショーにしなければならない）

# 意外と説明されてない「何ができないか」
いろいろなサイトやブログで「スライドショーにはこのjQueryプラグインが便利」と、いろんなものが紹介されています。

ところが、どこを見ても「この仕様には対応できない」というデメリットの説明はありません。

「こんなスライドショーの場合は対応できない」なんて説明があれば、探しやすいのですけどね...（いちいち試さなくて済む）
もっといえば、こんなスライドショーのときにはこのプラグイン、みたいに比較してまとめられていればもっといいのですが...

**ということで、実案件で困った事例も含めて少しずつここにまとめていこうと思います。**
Railsのインストールとオプション

## はじめに

新規でRailsのプロジェクトを立ち上げるときに、オプションを忘れてしまうことがしょっちゅうあるのでまとめてみました。

今回は「rails-sample」というプロジェクトを作ってサーバーを立ち上げるまでをやってみます。使っているオプションは僕の好みです。

## 前提

下記がインストール済み

- Ruby
- Bundler
- PostgreSQL

## 手順

### Railsのインストール

プロジェクトのディレクトリを作成

```
$ mkdir rails-sample
$ cd rails-sample
```

Gemfileを生成

```
$ bundle init
```

Gemfileのrailsのコメントアウトを外す

```
$ vim Gemfile
```

```ruby:Gemfile
gem "rails"
```

Railsをインストール

```
$ bundle install --path vendor/bundle --jobs=4
```

**オプション解説**

`--path vendor/bundle`
Gemをインストールするディレクトリを指定しています。

`jobs=4`
インストールの速度が上がるらしいのでつけてます。

### プロジェクト作成

```
$ bundle exec rails new . -B --skip-test -d postgresql
```

途中でGemfile上書きしちゃっていい？みたいなことを聞かれます。上書きしていいので「y」をタイプします。

**オプション解説**

`-B`
bundle installをスキップします。使わないGemがインストールされるのはいやなのでつけてます。

`--skip-test`
minitest使わないよーと明示してあげてます。これをつけるとtestディレクトリが作成されなくなります。僕はテストはだいたいRSpecを使うのでこのオプションをつけています。

`-d postgresql`
使用するデータベースをPostgreSQLに指定しています。だいたいPostgreSQLかMySQLのどちらかにしてます。

*その他オプション*

`--skip-turbolinks`
turbolinksを無効にします。

`--api`
API専用モードになります。

お好みでGemfileを編集

```
$ vim Gemfile
```

Gemをインストール

```
$ bundle install
```

DBを作成

```
$ bin/rails db:setup
```

サーバーを立ち上げて確認

```
$ bin/rails s
```

ブラウザでアクセス
http://localhost:3000

![localhost_3000_(Laptop with HiDPI screen).png](https://qiita-image-store.s3.amazonaws.com/0/261245/31c8cd4a-fc99-20c7-4381-2eaddc1a2e73.png)

OK！
ArchLinuxのVagrant boxでpacman -Syuするとinvalid or corrupted packageで失敗する

# 環境
- ArchLinux
    - Vagrant 2.1.5
- [ArchLinux公式Vagrant box](https://app.vagrantup.com/archlinux/boxes/archlinux) v2018.09.05 currently
    - 公式、と[ArchWikiに書いてあった](https://wiki.archlinux.jp/index.php/Vagrant#Vagrant_.E3.81.AE_Base_Box)

# エラー
```shell-session
# pacman -Syu
:
:: File /var/cache/pacman/pkg/bzip2-1.0.6-8-x86_64.pkg.tar.xz is corrupted (invalid or corrupted package (PGP signature)).
```

…みたいなのがいっぱい出てくる。

# 対処
[`pacman-key`のArchWiki](https://wiki.archlinux.jp/index.php/Pacman-key)にヒントが。

```shell-session
# pacman-key --populate archlinux
==> Appending keys from archlinux.gpg...
==> Locally signing trusted keys in keyring...
:
# pacman -Syu
```

…とやったら、うまくいった。

# その他の対処
- `pacman -S archlinux-keyring`
    - [こちら](https://www.ostechnix.com/fix-invalid-corrupted-package-pgp-signature-error-arch-linux/)にあった
- `pacman-key --refresh-key`
    - [`pacman-key`のArchWiki](https://wiki.archlinux.jp/index.php/Pacman-key)にあった
    - 数分〜10分くらい? かかる
シェルスクリプトで "set -o pipefail" を付けるとSIGPIPEで死ぬ

# はじめに

主にLinux環境で動くBashスクリプトについて書きます。

シェルスクリプトで、パイプを使ったコマンドを書く時に、安全弁として `set -o pipefail` を付けるのは良いマナーだと思います。
これにより、パイプの左側のコマンドが失敗したとき、スクリプトをそこで停止することができます。

```sh:pipefailの動作例
#!/usr/bin/env bash

set -eo pipefail

false | true
echo "won't be printed" # この行は実行されない
```

`false` コマンドは常に失敗するので、以降の行は実行されないというわけです。

# SIGPIPEで死ぬパターン

しかし、ここで1つ落とし穴があります。
パイプの左側のコマンドが通常は成功する場合でも、パイプの右側のコマンドによって `SIGPIPE` が発生することがあるのです。

例えば、次のようなパターンです。

```sh:SIGPIPEで死ぬケース
# 例1
cat some-big-file | head -n 10

# 例2
cat some-big-file | grep -q foo
```

この場合も、スクリプトは停止し、以降の処理は実行されません。

どうやら、上のようにパイプの右側で `head` や `grep -q` コマンドを実行した際、パイプがクローズされてしまい、クローズされたパイプへの書込みが発生することで `SIGPIPE` が発生すると推測しています。

# 回避策

trapコマンドなどを使ってスマートに対処できないか試しましたが、残念ながら上手く行きませんでした。
ワークアラウンドなやり方になりますが、以下に挙げておきます。

## ①SIGPIPEが発生しないようにコマンドを書き換える

上の例1, 2の場合、次のように書き換えられます:

```sh:回避策①
# 例1改
tac some-big-file | tail -n 10

# 例2改
cat some-big-file | grep foo &>/dev/null
```

## ②コマンドがエラーにならないようにする

例えば次のようにします:

```sh:回避策②
cat some-big-file | head -n 10 || true
```

`|| true` の効果で、このワンライナーは絶対に失敗しなくなります。
`|| :` などでも良いですね。

## ③ `set -o pipefail` を止める

そもそも使わないという選択もあり得ますが、部分的に無効化することもできます。

```sh:回避策③
set +o pipefail # オプション無効化
cat some-big-file | head -n 10
set -o pipefail # オプション再有効化
```

# まとめ

`set -o pipefail` を使う際はお気をつけ下さい。

# 参考

- [Man page of BASH](https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html) ... trapコマンドのリファレンス
- [Man page of SIGNAL](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html)
- [linux - Why exit code 141 with grep -q? - Stack Overflow](https://stackoverflow.com/questions/19120263/why-exit-code-141-with-grep-q) ... この問題を端的に表しているQ&A
- [Don't fear SIGPIPE!](http://www.pixelbeat.org/programming/sigpipe_handling.html) ... GNU coreutilsのメンテナの (at)pixelb がシェルスクリプト等におけるSIGPIPEの取り扱いについて書いています。どうもシェルスクリプトで完璧にやるには泥臭く終了ステータスを判定するしかないのかな、という印象ですが…。
- [第6回　UNIXプログラミングの勘所（3）：Perl Hackers Hub｜gihyo.jp … 技術評論社](http://gihyo.jp/dev/serial/01/perl-hackers-hub/000603) ... ネットワークプログラミングにおけるSIGPIPEの問題と取り扱い方について
Cloud9でTA-Libをインストールする


# Cloud9でTA-Libのインストールにつまづいたのでメモ
以下を実行

wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar -zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib
./configure --prefix=/usr
make
sudo make install

sudo bash -c "echo "/usr/local/lib64" >> /etc/ld.so.conf"
sudo /sbin/ldconfig
sudo pip install ta-lib
スマホで最短経路探索を使うとアプリが重くなる問題への対処メモ


## はじめに

スマホゲームで障害物ありの最短経路を求めたくなって、A*探索を使ったのですが、めちゃくちゃ重くなったので、それへの対策と効果の記録。

## 前提条件


- A*探索には[これ](https://github.com/lattejed/a-star-lua)を使用した。
- ゲームのルールは、障害物のある部屋で敵が主人公を追いかけてきて、主人公が捕まったらゲームオーバーになる、
- 主人公と敵は将棋盤のようなマス目を1マスずつ進む。
- 敵は500msごとに、主人公の現在地から最短経路を算出して、追いかけてくる。
- この条件で20×20のマスで遊んだところ、移動のたびに最短経路を算出しようとして重くなり、ゲームがカクついてしまった。
- 原因はA*探索に時間がかかっていること


## やったこと

### 移動のたびに計算をしない

最初は500msごとに最短経路を算出していたので、それをやめました。最短経路は4回に1回計算して、それ以外は以前に計算した結果を使用する。つまり、4回に3回は最短ではない経路を進む可能性がある。

結果は、多少は改善されたが、そもそものゲームのルールが崩れるので不採用。

### ゲーム開始時に全ルートの計算を行ってその結果をキャッシュする

ゲームがカクつかなければよいので、最初に全ルートの計算を行い、その結果をキャッシュし、最短経路の算出にはキャッシュを使うようにした。

結果は、ゲーム内のカクつきは改善されたが、ゲームが開始できるまで10秒ほど計算に時間がかかってしまったので不採用。しかし、計算結果をキャッシュする方式は有効なので、以降は全ルートの計算をいかに早くするかを検証した（目標は2秒以内）。

### 全ルートの計算の無駄をなくした

全ルートの計算における無駄をなくした。具体的には、A→B→C→Dという最短経路を見つけた際には、B~D間、C~D間そして逆のD~A間の最短経路は算出したものしてキャッシュ化した。

結果は、多少は改善されたが、ゲーム開始まで6秒ほどかかってしまうのでやはり不採用（正確にはこれだけでは不十分）。

## 結局…

計算の最適化はここまでにして、開発時に事前に計算した最短経路をJSONとして保持し、それを読み込む方式にした。全ルートの計算のJSONの容量は800KBくらいで、デコードさえしてしまえば全ルートの最短経路が使えるのでこれが現状のベタープラクティス。

しかしこの方式だと、 **マス目の数、障害物の配置が変わると、最短経路を計算しなおしてJSONも入れ替えないといけない** という問題点が残るので、引き続き調整は行いたい。

もし、知見がある方がいたらぜひアドバイスいただきたいですm(_ _)m
ソフトウェア設計についてのつぶやき（レビューとテスト）

[「ソフトウェア設計についてのつぶやき」](https://qiita.com/BlueEventHorizon/items/7b8dcf625ff5790ed1ef)を書き終わった直後に、「ああこれ書けば良かったっ」というのがありました。それは**レビュー**と**テスト**についてです。

（要件定義が大事という貴重なご意見も頂きました。ありがとうございます。もちろん何を作るのかが分かっていなければ設計どころの話ではありません。一応そこはなんとか乗り越えたとして話を続けたいと思います）

# ソフトウェア・レビュー

業界によるのかも知れませんが最近レビューというと「ソースコード・レビュー」と考える方が多くてびっくりしています。もちろん「ソースコード・レビュー」は大事ですし、さらにレビューを活かすための方法論も大事だと思います。しかしながら、そもそも**何をレビューすれば良いのか**を踏み外すと効率的なソフトウェア・レビューにならないのではないでしょうか。

[「ソフトウェア設計についてのつぶやき」](https://qiita.com/BlueEventHorizon/items/7b8dcf625ff5790ed1ef)で、ソフトウェア設計には３つの重要なステップがあると書きました。

```
分析: 責務を考える
設計: インターフェースを考える
実装: 実装を考える
```

このうち「ソースコードレビュー」は３番目の実装フェーズのレビューにあたります。つまり、分析も設計も終わっている後工程の成果物のレビューということになります。

テストやレビューが何のために存在しているかといえば、もちろんアウトプットである製品や商品、システムが間違いなく期待通りに動くことを確認・担保するということなのですが、もうひとつ製造プロセス上の重要なポイントが、**「間違っていた時、勘違いしていた時、不具合が見つかった時に、素早くローコストで訂正・修正するため」**、ということだと思います。
Qiita記事の[仕様／設計レビュー手法](https://qiita.com/nakaok/items/9eb5487a3375c72e3761)から下記を引用させて頂きます。

```
問題が発生した場合の修正コストは、下流工程に行けば行くほど大きくなることが知られています。
特に仕様漏れや設計ミスなどで手戻りが発生すると、プロジェクトの計画に影響を及ぼしかねない膨大な修正コストが発生します。
上流工程で問題を検出し、下流工程での問題発生を未然に防止することがレビューの大きな目的です。
```

であるならば、レビューはコーディングなどよりも上流工程である**分析、設計**の段階でを行う方が効率的なのではないでしょうか。

特に実装者と設計者が異なる場合は、実装者が設計の意図をちゃんと汲み取り、基本設計に忠実に実装（詳細設計）を考えているかは、重要なポイントになります。**詳細設計書を作成する時間が無い場合**でも、できる限りコーディングの前に基本設計者に実装方針の説明をしてアドバイスを貰うこと（ウォークスルーレビュー）は大事だと思います。

ソースコードが言語的に効率的に書かれていないとか、冗長であるとか、コーディングルールに沿っていないとか、Typoがあるとか‼️ はそのあとの問題です。（必要ですよ、必要ですけどね・・・という話）

# ソフトウェア・テスト

テストについても同様に違和感を感じることが多いので、それにも簡単にふれておきます。

![V字モデル](https://webrage.jp/wp/wp-content/uploads/2016/07/v_shaped_model.png)

上の図は[https://webrage.jp/techblog/v_shaped_mode/](https://webrage.jp/techblog/v_shaped_mode/)より引用しています。ありがとうございます。

これをよくウォーターフォール開発の図と勘違いする方がいます。が、そうではなくて開発プロセスの順番と、設計フェーズとテストフェースの関係を表した図となります。例えばアジャイルのような場合でも、これらのプロセスの一部を切り取ってイテレーションするような視点を持っていると良いのかも知れません。
それぞれの左側の設計と実装フェーズに対して、右側に対応するテストが存在し、そのテストは同じ階層の要件定義、設計、実装などからやるべき内容が導き出されます。

これを簡単に言えば、

```
テスト=設計
設計=テスト
```

ということではないでしょうか。

設計書（または要件定義書）に書いてある通りのことをテストするのがテストフェーズです。設計書（または要件定義書）に書いてなければテストはできません。何が正しいかが分からないからです。
テストの観点からプロセスを逆に見てみると、下記のような表になると思います。（内容は思いつき、かつ代表例なのでもっと良い表現があるかと思いますが）

| 分析・設計・実装（左側） | テスト（右側） | 内容 |
|:-----------------|:------------------|:------------------|
| コーディング | コードレビュー | コーディングガイドラインに沿っているか、より効率的な書き方はないかなど |
| 単体テスト | 詳細設計 | 実装した関数が期待通りの動きをするか。想定していない動きをしないか。 |
| 基本設計　| 結合テスト | モジュール間のシーケンスは設計書通りか、設計書に示されたモジュールの責務に対して過不足はないか　|
|要件定義|システムテスト|機能要件、非機能要件を満たしているか|
|要求分析|受入テスト|要求を満たすシステムとして稼働するか|

一般にエンジニアは単体テストに注目することが多いのですが、上流工程ではそれ以外の一連のプロセスがすべて下流工程であるテストに直結しているという視点を持つことはが大事なのではないかと思います。

ここまで書いてなんですが、そうは言っても設計書をきちんと書いて行くのは、時間的に、体力的になかなか難しいものがあります。自分への戒めも込めて本記事を書かさせて頂きました。
シェルからrsyslog経由でログ出力する

シェルスクリプトからrsyslog経由でログを書きます。シェルで何かの機能を提供していて、実行者（非root）にログ編集／改ざんさせない仕組みを作れます。

# やりたいこと
・非rootユーザで実行するシェル内で文字列をログに出力する
・上記ログはシェル実行ユーザでは参照／編集できない
・ログ出力パス：/var/log/test.log

**シェル内のログ出力部分**

```bash
logger -p local0.6 'log write'
```

**rsyslogの設定**
※事前にlocal0を使っていないことを確認する

```config:/etc/rsyslog.d/test.conf
local0.6 /var/log/test.log
```

**ログ出力例**

```bash
$ ls -l /var/log/test.log 
-rw------- 1 root root 50  9月 14 00:40 /var/log/test.log

$ cat /var/log/test.log
Sep 14 00:40:55 kusakari: log write
```

**（参考）ログの分割設定を入れておきたい**

```config:/etc/logrotate.d/test.conf
/var/log/test.log {
    missingok
    compress
    delaycompress
    notifempty
    daily
    rotate 1000
    create 0600 root root
}
```
スピナー　ほんとに基本部分

※あくまで自分のメモ用です！

# スピナーの基本的な使い方について

スピナー…今回はこんなん。
![spinner.PNG](https://qiita-image-store.s3.amazonaws.com/0/284198/98d4f2be-5af8-1bec-ace5-f08d7c9f0946.png)

### スピナーを入れたいレイアウトxmlにspinnerを追加
spinnerModeが
　・dropdown(デフォルト) = モードレス
　・dialog = モーダル
のイメージ。

```java:layout.xml
<Spinner
    android:id="@+id/spinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:spinnerMode="dialog" />
```

### リストに表示させるitemの設定
strings.xmlにarray形式で持たせる。
(java内で設定するのはこの後で)

```java:strings.xml
<resources>
    <string-array name="SampleArray">
        <item>A</item>
        <item>B</item>
        <item>C</item>
    </string-array>
</resources>
```

### Javaでリストの設定
アダプタ使って、スピナーにリストの値を設定する。

```java:なんとか.java
        Spinner spinner = findViewById(R.id.spinner);
        ArrayAdapter adapter = ArrayAdapter.createFromResource(this,R.array.SampleArray,android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.select_dialog_singlechoice);
        spinner.setAdapter(adapter);
```

2行目：アダプタ生成時
R.array.SampleArrayで、strings.xmlの設定を渡してる。
java内で配列作って渡すか、adapter.addで追加してやってもok。
動的になるならこっちでやるのかな。

3行目：ドロップダウンの設定
android.R.layout.○○
　select_dialog_singlechoice：ラジオボタン
　simple_spinner_dropdown_item：アイコンなし

以上！
Alexaのiftttトリガーがうまく反応しないときの確認方法

Amazon echo を購入し、iftttトリガを使ってみたものの、なかなかうまく動いてくれず、
どうしたもんかと思ったときに、動作を確認した。

# そもそも、Alexaはどう解釈したのか？
先にも後にも、結局Alexaがどう解釈したのかがわからないと進めない。

Alexaがどう聞き取ったのかは、Alexaアプリで確認できる。

1) Alexaアプリの右下ギアのアイコンをクリックして、設定を開く
![右下ギアのアイコン](https://qiita-image-store.s3.amazonaws.com/0/19870/09b4c934-09ad-ecef-6690-8c33a92181b8.png)

2) Alexaアカウントの「履歴」を開く
![履歴](https://qiita-image-store.s3.amazonaws.com/0/19870/5dd3c883-e53c-957c-f5d5-d74ee06e4a72.png)

3) 履歴の一覧を確認
Alexaが何と理解したか、記録されます。
![履歴一覧](https://qiita-image-store.s3.amazonaws.com/0/19870/f88a5c28-b592-e160-22fa-6a8179638a9a.png)

4) さらに詳細に確認する場合は、実際の履歴行を開く
![履歴詳細](https://qiita-image-store.s3.amazonaws.com/0/19870/2e6ae537-30ee-f405-b013-e223af216717.png)

# 問題を切り分ける
なんと理解したかがわかったところで問題を切り分けます。

## 1) こちらが意図した言葉にそもそもなっていない

こればっかりはAmazonが精度を上げてくれることを待つしかありませんが、
自分でもできることとすれば、Alexaが高い精度で解釈してくれるワードを探すこと。
例えば、トリガのフレーズが長かった場合はにしていた場合は短くしてみるなどすると
多少改善しそうです。

## 2) 設定済みトリガフレーズとの差異を確認する

ひらがな/カタカナ/漢字/アルファベットの違いがないか、確認してみましょう。
日本語を設定した環境特有なんだと思うのですが、
トリガフレーズに設定した「文字列」と一致していないと起動しないようです。

# 私の改善例

私が実際に確認した2ケースを記録のつもりで記載しておきます。

## 「おためし」 vs 「お試し」

 - トリガフレーズに「おためし」と設定
 - Alexaの理解は「お試し を トリガー」

上記を確認したので、トリガフレーズを「お試し」に変えたところ、正しくトリガが起動するようになりました。

## 「パパ呼び出し」 vs 「パパを呼び出し」

ちゃんと確認していませんが、「は」「が」「を」などの接続語ぐらいは多めに見てくれる可能性があります。

 - トリガフレーズに「パパ呼び出し」と設定
 - Alexaの理解は「パパ を 呼び出し をトリガー」 ※「を」の前後にはスペースがあるように見えます。

上記の場合は、「パパ呼び出し」と設定したトリガは起動しました。
技術的負債との付き合い方

#はじめに
先日、「技術的負債との付き合い方」についての勉強会に参加してきました。
こちらは２記事構成で、[技術的負債とは](https://qiita.com/ginokinh/items/f1af0201169995c8f054)の続編記事となります。

- [技術的負債とは](https://qiita.com/ginokinh/items/f1af0201169995c8f054)
- 技術的負債との付き合い方 ←（本記事）

#技術的負債との付き合い方
まず、技術的負債へのアプローチの方法は二つあり
**・今後の負債を増やさない方法**
**・現在ある負債を減らしていく方法**
この二つです。この記事では二つのアプローチ方法からどのように`技術的負債と付き合って行くのか`について記載します。

##負債を増やさない方法
###「Railsが提供している便利な機能を活用する。」
負債の原因の一つとして、便利な機能を知らずに自分で実装して微妙になるケースがよくあります。
=>なので、`こんなメソッド無いかな？`と調べてみる。
<対策>
・公式のドキュメントやRailsガイドを読んで調べてみる。
・もしくは強い人に聞いてみる。

便利な機能を活用することで
**・コードの読みづらさ
・バグの数
・差分をみてinsert,deleteをする手間**
等を抑えることができます。

###「要注意な機能/gem等をチーム全体で周知しておく」
便利な機能とはいっても無条件に使用できるものではないので、チーム内で要注意なものに関しては
・なぜ注意が必要なのか。
・どう避けるのか。
・どうときなら使っていいか。
をチーム内で詳細を詰めて共有しておくと、無駄な負債を増やさなくて済みます。

###「定期的に$bundle update をする」
その名の通りです。めんどくさがって後回しがちですが、タスク管理して業務フローに入れ込むくらいがいいです。
例えば、Railsのバージョンをあげるときに、gemの仕様が古いとこのアップデートに時間がかかってしまいます。
これを後回しにした結果**さらに後回しをする**羽目になります。もう**借金地獄**です。

<対策>
*「Bundle Update Flow」*を組んでやる。
例えば、
・二週間に一回はする。
・（チーム開発であれば）当番制にする。
などタスク化することです。

この小さな取り組みが大きな負債を産まずに済むので、是非僕も気をつけていきたいところです。

##負債を減らしていく方法
###「いけるいけるという強い気持ちをもつ」
気持ちといって軽視する人もいると思いますが、この気持ちさえあれば負債を減らして可能だと思います。
しかし一人で気持ちを継続することは難しいですし、いくら根性がある人でも限界があると思います。

どう継続して行くか？ => それは**「仲間とやる」**です。

###気持ちで負けないためのモバプロ
「仲間とやる」方法としては`ペアプロ`,`モブプロ`をして、仲間とともに負債を減らして行くという方法です。

<メリット>
・一人でだと挫折してしまうコードを仲間と一緒だと読める。
・仕様,背景の理解が進む。（一人でやる以上に）
・出来た時の達成感を共有することができる。
・無視したいくらいの負債をその場で解決しよう。となる。

上記のように、
複数でやっていると軽視しがちな**「小さな成功体験」**を感じながら進めることができるので
より**「いけるいけるという気持ち」**が強くなり、気持ちも育てることが出来ます。

ただ、「一人で書いた方が効率がいいし、他の人にコードを見られながら開発したく無い。」と思う方も多いかと思います。

**しかし、重きを置いているのは負債を減らすこと。問題解決です。**

効率がよく開発するのはいいことですが、ソロプロで早いのはPRまでの時間です。
大切なのは、**PRのマージ（リリース）までにかかる時間**です。

###「とにかく頑張る」
最後に、あとはとにかく頑張るです。作ってしまった負債は頑張ってコードをじっとみて
不要なコード/gemは削除して行くことです。
頑張らずして負債が勝手に減ってくれる様なことは起こりえません。
誰かが負債を削除してくれたとしても、それはやはりその人が頑張ってくれたからです。
なので、最後に書きました。**「とにかく頑張る」**です。

#終わりに
最後まで読んでくださりありがとうございました。
また間違ったような表現などありましたら、ご教示いただけますと幸いです。
よろしくお願いいたします。
調査会社の市場予測は当たるのか (IDC Japanによるパブリッククラウドサービス市場予測)

# はじめに

調査会社が予測した市場規模の値を使って、X年後の市場規模がこのぐらいで、弊社はこのぐらいシェア取りたいから、予算をこのぐらい取ろう、なんてやっている人がたくさんいると思いますが、そもそも市場規模の予測って当たっているのか。過去の予測値を検証した例が見当たらなかったので、一例としてまとめてみました。

#パブリッククラウドサービスの市場予測の例

IDC Japanによるパブリッククラウドサービスの市場予測が、2008年から継続的に行われており、過去のプレスリリースをweb archiveから拾えたので、こちらを例としてまとめてみました。

![IDC Japan によるクラウド市場規模の実績推定値 と予測.png](https://qiita-image-store.s3.amazonaws.com/0/283474/152cf867-5294-9dbc-bca7-fc2325d0c04c.png)

横軸が予測した年で、その年の実績推定値と共に5年後の予測値が出されてます（2009年だけ4年後の予測値だったので省いてます）。

2008年〜2010年のプレスリリースではクラウドの市場予測と記載されておりパブリッククラウドと明示されてませんでした。ただし、2009年および2010年はプライベートクラウドの市場予測のプレスリリースが別途出ており、これよりも大きな値が予測されていたので、おそらくパブリッククラウドの市場予測だと思われます。

パブリッククラウドサービスの市場として何を含めているのかはプレスリリースには明示されてませんでした（レポートには書かれていると思いますが、見てません）。年によって何を市場に含めているかが変わっている可能性があります。そのため、予測が実績推定値とずれているからと言って、必ずしも予測が外れたとは言えない可能性があります。例えば、2009年の実績が596億円と出しているにもかかわらず、2010年の市場規模が前年比で45.3%増の454億円とプレスリリースには書かれており、値が合いません。

#結果

実績と予測が共に出ている年は、2013年、2015年〜2018年だけですが、その後の予測値を見ても実績は予測よりもかなり上振れしているように見えます。

そもそも当たると思って予測値を使っている人などいないのかもしれませんが、予測の実績を知っておくと良いでしょう。
python37版のgoogle app engineを動かすのにとても手間取ったお話

結論から言うと、python27とpython37の**両方**が動かせないと、開発できなかった:frowning2:

# python37 beta!!

という訳でgaeにbeta版ではありますが[python37](https://cloud.google.com/appengine/docs/standard/python3/runtime)のruntimeがgaeに追加されました。
python2.7の寿命のことを考えると非常にありがたいですので、早速使ってみました。

# python37のinstall

```terminal
$ pyenv install 3.7.0
$ pyenv global 3.7.0
```

とまぁ、こんな感じでルンルン気分で3.7.0をインストールして、2.7から切り替えてみました:laughing:

# 動かないdev_appserver.py

3.7版の簡単なhello worldも書けた、さぁデバッグだ！
[参考](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/standard_python37/hello_world)

```terminal
$ dev_appserver.py .

ERROR: Python 3 and later is not compatible with the Google Cloud SDK. Please use Python version 2.7.x.

If you have a compatible Python interpreter installed, you can use it by setting
the CLOUDSDK_PYTHON environment variable to point to it.
```

Google Cloud SDKがpython3.7.0に対応していない……だと……:dizzy_face:

# 動かし方

つまり、python37でgaeをlocalにて開発するのにあたって……

- dev_appserver.pyはpython2.7.xで動かす必要がある
- python37版のソース自体はpython3.7.0で動かす必要がある

ということでした:kissing_heart:

なので、dev_appserver.pyを直接実行するのではなく、python2.7の引数に渡してあげる形にしてあげます。

```terminal
$ python --version
Python 3.7.0
$ CLOUDSDK_PYTHON=~/.pyenv/versions/2.7.12/bin/python
$ $CLOUDSDK_PYTHON /hogehoge/dev_appserver.py .
```

動いた:stuck_out_tongue_closed_eyes:
毎回この手のを設定するのもめんどくさいので、aliasを切って確実に2.7.12で動くようにするのも有りかも！

# Pycharmでpython37版のgaeを動かしたい！

うん、サポートしていないんだ、それは:alien:


python27で全てを動かすか、37でプロジェクトを動かすかの2択しか取れない……！
が、27にするとpython37のruntimeは動かせないし、37にするとdev_appserver.pyが動かない！

起動はもちろんデバッグもできない……！　不便！！！
早く正式対応して欲しいところ:thinking:
【セミナー参加】レトロゲームからUXを学ぶ会　～第1回 ファミコン編～

こんにちは、@tacashionです。

# レトロゲームからUXを学ぶ会

先日、HCD-Net関西支部主催の
[レトロゲームからUXを学ぶ会　～第1回 ファミコン編～
](https://peatix.com/event/416042?lang=ja)に参加してきました。

![6D4971DB-4B03-4908-B18A-A5D8221EEAE1.jpeg](https://qiita-image-store.s3.amazonaws.com/0/289530/15bc3391-f00b-abd8-8ae4-8f377938f23a.jpeg)
_会場は、素敵なイベントスペースが併設されている「[さくらインターネット株式会社](https://www.sakura.ad.jp/)」さん_

## レトロゲーム✕UX＋日本酒
> 発売日を待つワクワク感、プレイ時のドキドキ感・ハラハラ感、プレイ後の達成感やもう一度やりたくなる気持ち。
> まさにUXに溢れていた毎日でした。きっとそこには、いまでも活かせる要素がいっぱい詰まっているに違いありません。

「名作はUXが優れているのでは？」という仮説のもと、5人のファミコン世代の登壇者の方々がレトロゲーム（今回は任天堂・ファミリーコンピューター）について熱く語るという珍しい趣旨。

そして、このイベントのさらなる特色は、登壇者の方の一人が「[浅野日本酒店](http://asano-nihonshuten.co.jp/)」のオーナーの浅野洋平氏であり、アフターパーティーでは浅野さんセレクトの日本酒が楽しめるというオマケ付き、という点。

## グラディウス✕UX

人間中心設計推進機構 理事・関西支部長（元コナミ）水本 徹さんのLTでした。

ビックバイパーという戦闘機が主役のシューティングゲームである「グラディウス」それは水本さんのユーザーリサーチの原点とも言える作品だったそうです。

その理由は「ロケテスト」
当時、ゲームセンターの1㎡あたりでいくら稼げるか、というものがKPIとして設定されていたそうで、毎日ゲーセンに通ってはゲームをしているユーザーを観察し、いかに長く、多く遊んでもらえるかを考え、改善を繰り返していたそうです。

![6848F505-87BA-45BF-9DAB-E3344C410001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/289530/0a78e5d8-a32e-85bc-77fc-8e1a54a3cbc6.jpeg)

## What is UX in GRADIUS

グラディウスのUXの、重要な要素を3点、挙げられていました。
それは、

* Growth
ビックバイパーが成長する

* Fail
スピードUPしすぎて制御不能に
技の選択を誤ってレーザーからダブルショットにスペックダウン
バリアのタイミングを計算しすぎて大破

* Retry
大破したら最初からやり直し、プレイヤーが成長できる
この3点を繰り返すことによってユーザーがビックバイパーと共に成長するというUXが実現されているとのことでした。

確かに、反復することによって以前出来なかったことができるのを実感すると、更に先にチャレンジしようという気になるかもしれませんね…！

![25768AAF-099F-49EA-B479-413475DB6AEB.jpeg](https://qiita-image-store.s3.amazonaws.com/0/289530/40f387f1-69af-ed68-fd8d-5b611c4ffcbc.jpeg)

## ディープなレトロゲーム4点…

その後、会場であるさくらインターネット株式会社の他に、ヤフー株式会社、浅野日本酒店の登壇者の皆さんが、以下のソフトの熱いレトロゲームLTをされました。

* 魂斗羅
* キテレツ大百科
* ファイナルファンタジーⅢ
* 天外魔境Ⅱ

皆さんクオリティ、世界観、音楽など様々な切り口で思い入れの深いゲームを紹介されており、大変熱量の高いLTとなっていました。
それぞれ発売後約30年はたとうというものなのに、ここまで心に爪痕を残すゲームというのは確かにすごい……！

## 講演後はお楽しみタイム

全てのLTを聴いた後は、実際にファミコンをプレイするコーナ＋日本酒タイム！
先程講演で登場したゲームはもちろん、ファミコンミニなども用意されていて、日本酒を飲みつつ、ゲームをして自然と会話も弾み…という、
しる→する→またしたい
の素晴らしいUXが体現されていたイベントでした。

<img width="768" alt="E6198FA3-1097-406D-950C-293FF4C21E57.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/289530/5e626d85-32b4-214b-eddd-9188afdefeda.jpeg">
_「キテレツ大百科」ではサイケな世界観で盛り上がる_

<img width="768" alt="C0EEF45D-3F2F-40D9-B91A-59BD3E49FD15.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/289530/8e0795cb-e98e-68ef-60f1-10a580828e75.jpeg">
_日本酒がズラリ…_

## おみや

最後、余った日本酒を巡ってじゃんけん大会が行われたのですが、そこで選択権2位をゲットし、高知の「[酔鯨](https://www.tosashu.com/menu/tosashu/suisummer.html)」をいただきましたw

<img width="768" alt="76F62540-C435-4164-B0F2-FDDA523239BB.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/289530/a077d09b-a080-824e-8b43-b7b74bcbdf4b.jpeg">
_夏限定の素敵なパッケージ_

さらに、いつも会社で利用しているアプリケーションを提供している会社の方に出会えたりと、社外イベントに参加するのも良いなと思い、このイベントそのものが、良いUXを生み出しているなと感じました。
HeimdalでKDCを多重化する

# 動機
Kerberosで認証サーバーを立てているが、1台しかない認証サーバーが死ぬと、全部死ぬ。
Kerberosって、多重化できないの?
[本家](https://www.h5l.org/manual/HEAD/info/heimdal/Incremental-propagation.html)を見ながらやったらできたっぽいので、メモ。
思い出しながら書いているので、抜けがあるかも。

# 前提
- 元々KDCが動作している環境であること

# 環境
OS選択に深い意味はありません。

## 元々動作しているマスターKDC
- OpenBSD 6.3
- Heimdal 7.5

## これから立てるスレーブKDC
- FreeBSD 11.2
- FreeBSD付属のHeimdal

# KDCを指定する設定
## krb5.confの場合
`[realms]`セクションのレルムのブロックの中で、`kdc`の行を、複数記述する。

```:krb5.conf
[realms]
EXAMPLE.ORG = {
                kdc = kdc1.example.org
                kdc = kdc2.example.org
                :
}
```

krb5.confのサンプルを見ると、KDCが複数あるレルムがあることに、今気づく。

## DNSのSRVレコードの場合

SRVの行を、複数記述する。
[HeimdalのDNSの説明](https://www.h5l.org/manual/HEAD/info/heimdal/Setting-up-DNS.html)によると、[RFC2782](https://tools.ietf.org/html/rfc2782)を見よとある。
[RFC2782](https://tools.ietf.org/html/rfc2782)では、`SRV`の後に続く数値は、優先度で、数値が小さい方が優先度が高い。

```:zone-file
_kerberos._udp          IN      SRV     0 0 88 kdc1.example.org.
_kerberos._tcp          IN      SRV     0 0 88 kdc1.example.org.
_kerberos._udp          IN      SRV     10 0 88 kdc2.example.org.
_kerberos._tcp          IN      SRV     10 0 88 kdc2.example.org.
```

これも、[HeimdalのDNSの説明](https://www.h5l.org/manual/HEAD/info/heimdal/Setting-up-DNS.html)の例で、SRVが複数あることに、今気づく。

# マスターKDCの設定
## プリンシパルの追加
`host/ホスト名`に加えて、`iprop/ホスト名`を追加する。

```shell-session
kdc1# ktutil get -p hoge/admin host/kdc1.example.org
kdc1# ktutil get -p hoge/admin iprop/kdc1.example.org
```

実際には作ったのを持ってきて設置してしまったので、動かなかったらすいません。
[本家](https://www.h5l.org/manual/HEAD/info/heimdal/Incremental-propagation.html)で`ktutil get`初めて知った…。

## スレーブの指定
`/var/heimdal/slaves`に、プリンシパルで指定する。

```:/var/heimdal/slaves
iprop/kdc2.example.org@EXAMPLE.ORG
```

## `ipropd-master`を起動する
```shell-session
kdc1# rcctl ipropd-master enable
kdc1# rcctl ipropd-master start
```

# スレーブKDCの設定
## プリンシパルの追加
`host/ホスト名`に加えて、`iprop/ホスト名`を追加する。

```shell-session
kdc2# ktutil get -p hoge/admin host/kdc2.example.org
kdc2# ktutil get -p hoge/admin iprop/kdc2.example.org
```

## m-keyの設定
マスターから`/var/heimdal/m-key`を持ってくる。
…で、合っているんだろうか。

## rc.confの設定
`kdc`と`ipropd_slave`を動くようにする。
`ipropd_slave_master`とはややこしい名前だが、`ipropd_slave`に指定する、マスターの名前。

```:/etc/rc.conf
kdc_enable="YES"                        # Run a kerberos 5 KDC (or NO).
kadmind_enable="NO"             # Run kadmind (or NO)
kpasswdd_enable="NO"            # Run kpasswdd (or NO)
ipropd_slave_enable="YES"       # Run Heimdal incremental propagation daemon
                                # (slave daemon).
ipropd_slave_master="kdc1.example.org"               # master node name.
```

## 起動
```shell-session
kdc2# /etc/rc.d/ipropd_slave start
kdc2# /etc/rc.d/kdc start
```

# 確認
## マスターでの転送状況の確認
```
kdc1# cat /var/heimdal/slaves-stats
Status for slaves, last updated: 2018-08-24T03:19:42

Master version: 36

Name                         Address              Version  Status  Last Seen
iprop/kdc2.example.org@EXAMPLE.ORG  IPv4:192.168.100.11       36  Up      2018-08-24T03:17:42
```

何か転送されているらしい。

## マスターの停止
```shell-session
kdc1# rcctl stop kdc
```

## kinit
```shell-session
kdc2$ kinit hoge@EXAMPLE.ORG
kdc2$ klist
```

数秒待った後、チケットが取得できていれば、スレーブを参照している模様。