OmniAICreator/Qiita-1.07M huggingface dataset:
lighttpd マルチスレッド化にトライ！

##**はじめに**

最近lighttpdについて色々まとめていましたが、それは私がずっとlighttpdに対して持っていた疑問の深堀をしたかったからです。
**なんでシングルスレッドなのに速いの？**

また、私は今[作成したOSS design_pattern_for_c](https://qiita.com/developer-kikikaikai/items/c504a1963310e2842849)のサンプルコード作成対象として適切な相手を探していました。
作成したOSSはライブラリパッケージなので、目的のちゃんとしたシステムで一発サンプルを作らないと、面白いパッケージになっているのかが正直見えてこないんですよね。

そんな私の2つの思いを解決する手段として思いついたのがこれ。
**design_pattern_for_cを利用して、lighttpdをマルチスレッド化してみよう！**

この記事では、まずはやろうとしていることを公開して逃げ道をなくし、今後、作業進捗とともにわかったこと、有益だと感じたことを記事内で更新していこうと思っています。
なので今はなんの結果も詰まっていないポエムみたいなものです。

実施コードは[こちら](https://github.com/developer-kikikaikai/lighttpd_multithread)

## **基本方針**

### **目的**

1. lighttpdをマルチスレッド化して比較測定を行う
2. lighttpdの修正を通して、**高速・軽量**を実現している工夫を探る。
3. design_pattern_for_cがライブラリパッケージOSSとして有用になるよう、issueを沢山洗い出す。


### **成果物**

サンプルを2～3段階に分けて作成します。条件は以下:

- プラグインAPI, よく利用されるAPIの動作in/outは変えず、lighttpd向けに実装したプラグインはそのまま利用できるようにする。
⇒そうしないと比較にならないため。今まで作ったcgi/プラグインの利用で比較。

- 比較測定結果を提示する。
    - 速度 -- HTTPは[weighttp](https://github.com/lighttpd/weighttp)を、HTTPSはSSLyze辺りの複数実行で試してみる。その他いい案があれば更新。
    - 軽さ -- 上記実行中のCPU使用率、メモリ使用量を比較します。
- 比較対象
    - lighttpd 1.4.49
- 保証動作環境
    - Ubuntu 18.04 Desktop

##**構想**

今のところ、このような方針で作業を考えています。

- 第一弾
    - design_pattern_for_cのStateMachineを利用してセッションごとにマルチスレッド化 ～ シングルスレッドとの速度比較の為

- 第二弾
    - ヘッダー情報のストレージ: HTTP/2のように出来るだけ作成したヘッダー情報を流用して速度向上を目指す。 ～ Flyweight(もしくは未作成のPrototype)の利用
    - fdeventは活かすが、ソケットの扱いが変わるはずなのでイベントの制御をPublisherを利用して置き換える。 ～ PUblisher使用感確認も兼ねて
        - 必要に応じてdesign_pattern_for_c側にFDを利用したライブラリAPIを追加
    - design_pattern_for_cのchain_of_responsibilityを利用して、プラグイン処理の置き換え ～ chain_of_responsibility使用感確認も兼ねて
    - その他今の構成に合った形で無駄なデータを削除

##**結果予想**

- 第一弾での比較
    - 速度はトントンか少しだけ向上、後は惨敗

- 第二弾での比較
    - 速度はもう少しだけ向上、後は惜敗

- 結論予想
   - **YLS(やっぱりlighttpdはすごい！)**

作業中に気付いたlighttpdの凄い所があれば、別途まとめて行きたいと思います。

## **進捗**

2018/06/16
　第一弾 F5連打に何とか耐えられるレベルまでは作成出来たが、weighttpで計測できるレベルに至らず。lockだらけになったので返って遅くなりそうな気配

##**ちなみに**

別に投稿者はlighttpdに不満があってリファクタしてやろう！って思ったわけではないです。
実際HTTP仕様の更新や脆弱性への対応も早いですし、導入も簡単だし。(プラグイン周りでは不満もありますが、どんなツールにも多少の不満はあるものですよね？)

ただこんな感じに色々な要素が積み重なっただけで、悪意はないのであしからず。

- ライブラリを適用してみる大き目のシステムとしてHTTPサーバーは適切だった
- 純粋にlighttpdがどう強力なサーバーとして動作しているかが気になっていた
- 仕事で何度か中をデバッグしたことがあり、多少は中身を把握していた
Nuxt.js + Storybookでsass-resouces-loaderを使う

Nuxt.js で sass の共通変数を扱うには、nuxt-sass-resources-loader が便利ですが、さらに Storybook を導入したところ、sass-resources-loader の設定にかなり苦戦したので覚え書きです。

## 前提
- Nuxt.js のスターターテンプレートを利用
- Vue の単一ファイルコンポーネントで scss 記法を利用

詳細は参考資料を参照ください。

## loaderのインストール

sass 関連の loader をインストールします。

```shell
$ yarn add -D node-sass style-loader css-loader sass-loader sass-resources-loader
```

## webpackの設定

.sotrybook 配下に以下の記述をした webpack の設定ファイルを用意します。

```js:/.storybook/webpack.config.js
const path = require('path');

module.exports = (baseConfig, env, defaultConfig) => {
  // vue-loader の参照を取得します
  const vueLoader = defaultConfig.module.rules.find(({ test }) => {
    return test.toString() === '/\\.vue$/'
  })

  // vue-loader の設定をします
  vueLoader.options = {
    loaders: {
      scss: [
        'style-loader', 'css-loader', 'sass-loader',
        {
          loader: 'sass-resources-loader',
          options: {
            // 共通で利用する変数やミックスインを定義したファイルのパスを定義します
            resources: [
              './assets/sass/_variables.scss',
              './assets/sass/_mixins.scss'
            ],
            include: path.resolve(__dirname, '../')
          }
        },
      ],
    },
  }

  return defaultConfig;
};
```


## 参考資料

- [Nuxt.jsにStorybookを導入する](https://qiita.com/masaakikunsan/items/28c66a5f89b6c6e14e3d)
- [《Nuxt.js》Sassの共通の変数やmixinを一括で各コンポーネントに読み込む方法。](https://qiita.com/uto-usui/items/6b745203fa6fad577877)
- [React Storybookを導入するときに知っておくと良いconfigまわりのこと](https://qiita.com/zaki-yama/items/ef2b05a6e60f37701c0d)
ある階層の固定ページのステータスを保存時に"予約投稿"から"公開済み"にする

以下のコードは、`id=xxxx`の固定ページの子要素で"予約投稿"を無効化して、強制的に"公開済み"にする。

```function.php
// 予約投稿を公開済みに変更する

function force_publish_page( $data, $postarr ) {
  if (
    $data['post_type'] == 'page' && 
    $data['post_parent'] == xxxx && 
    $data['post_status'] == 'future'
   ) {
    $data['post_status'] = 'publish';
  }
  return $data;
};
add_filter( 'wp_insert_post_data', 'force_publish_page', 10, 2 );
```
Excelでカレンダーを作ってみる

# 出荷一覧をカレンダーに表示

[【Excel】Excel でカレンダーを作ってみる](https://qiita.com/taopi/items/b81f2cd0bfffe51f5cfa)を見たからではないのですが、
実は、カレンダーに年月指定で、出荷状況を表示する機能を作っていました。
最初のは余りにも力技で、そのままのコードは汚いので、少し見易く整理をしました。

# カレンダー本体は、テーブル
カレンダー本体(名前はSKCAL_)とコントロールテーブル(名前はCAL_)はテーブルで作成します。

![CAL.png](https://qiita-image-store.s3.amazonaws.com/0/184069/10b22f8b-9b11-c9be-1911-8de948f289fe.png)

# 関数を２つに分けました

無理やり１つの関数にまとめると雑になりすぎるので、日付部分と出荷状況表示の２つに分けました。
CALAは、年月からカレンダー日付のシリアル値を求める関数です。
日付計算が何故IF文なのかですが、IFC で纏めると循環していると判断されるようです。
年月で発火すればいいので、参照先のテーブルは、文字列で定義しても問題ないようです。
DateSerialの結果を変数で受けるのは面倒なので、２回計算しています。

```vb
Function CALA(年, 月, Optional T = "SKCAL_", Optional S = 0)
    Dim R: Set R = Range(T)
    Dim M: M = MM(R)
    Dim N: N = NN(R)
 
    If M = 1 And N = 1 Then
        S = DateSerial(年, 月, 1) - Weekday(DateSerial(年, 月, 1)) + 1
    Else
        S = DI(R, 1, 1) + 7 * Int(M / 2) + N - 1
    End If
    CALA = S
End Function
```
CALBは、出荷一覧（名前はSK_）から日付をキーにデータを持ってきて編集し表示します。
CALAで計算した日付シリアルを引数Dで受けて発火してくれるので、出荷一覧テーブルは文字列指定で問題ないようです。
調子にのって引数全部をOPTIONALにすると、再計算してくれなくなるようです。

```vb
Function CALB(D, C, Optional S = "")
    Dim 年, 機, 番号, W, O, 製品名, 発注, 依頼, 日付, 出庫, 済, 在庫, I, J, K
    J = MI(Range("SK_[日付]"), D)
    K = Range("SK_").Rows.Count
    
    For I = 1 To K
        If J = "" Then Exit For
            
        Call DR(Range("SK_"), J + I - 1, 年, 機, 番号, W, O, 製品名, 発注, 依頼, 日付, 出庫, 済, 在庫)
        
        If 日付 <> D Then Exit For
        
        If W > 0 Then 製品名 = CC(製品名, "(W", TF(W, "000"), ")")
        S = CC(S, Left(CC(製品名, SP(15)), 17), " ", TF(出庫, "###0"), IFC(機 = 1, "本", "個") _
                                                                     , IFC(済 = 0, "", C), vbNewLine)
    Next I
    CALB = S
End Function

Sub DR(R, I, ParamArray PA())               ' DATA READ
    Dim J: For J = 0 To UBound(PA)
        PA(J) = DI(R, I, J + 1)
    Next J
End Sub
```

# 使用法

１行１列(B3):　=CALA(CAL_[年],CAL_[月])
２行１列(B4):　=CALB(B3,CAL_[済])

と定義し、B3,B4を纏めてCOPYし、関数で全体にPASTEして下さい。

以上
Dockerにネットワーク経由でアクセスする方法

### 本記事について
Docker が動いているマシンに、ネットワーク越しに、別のクライアントから Docker にアクセスできるようにする方法。

## はじめに
Dockerはサーバー・クライアントで動いています。
ローカルのPCにDockerをインストールした際は、同じPC上にサーバー・クライアントが構築され、直接通信を行います。
その通信をネットワーク越しに行えるよう設定することにより、他のPCで動いているDockerでも、ローカルのDockerで作業するのと同じ感覚で、操作ができるようになります。

## Docker Machineでネットワーク通信をセットアップ
Docker をネットワーク通信できるようにする方法は、公式の https://docs.docker.com/engine/security/https/ に記載されていますが、結構手間です。
そこでここでは、Docker Machineを使って、Dockerをネットワーク通信できるようセットアップします。

### Docker Machineとは
- Dockerサーバーを作成・管理するためのコマンドです。
  https://docs.docker.com/machine/
- 新たにDockerサーバーを作ったり、既存のサーバーをDockerサーバーにすることができます。
- サーバーにするPCは何でもよく、仮想PCでも構いません

### Docker Machine構築
既にPCがあって、それをDocker Machineにする方法を記載します。

- (サーバー側作業)サーバーにSSHログインできるようセットアップしておく
- (サーバー側作業)サーバーでSSHログインユーザーがsudoをパスワード無しで実行できるようにしておく
- ``docker-machine``コマンドをインストール https://docs.docker.com/machine/install-machine/
- Genericドライバーで、サーバーをDocker Machineにする<br>
  Dockerは自動でインストールされるので、インストールしておく必要はありません

```sh
docker-machine create \
    --driver generic \
    --generic-ip-address=<IPアドレス> \
    --generic-ssh-key <ssh鍵ファイルパス> \
    --generic-ssh-user <sshログインユーザー名> \
    <マシン名>
```

これで、指定したPCがDocker Machineとなります。
作成されたDocker Machineではdocker daemonがネットワーク通信可能な状態でセットアップされています。

```sh
$ ps -aux | grep dockerd
… usr/bin/dockerd -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock --storage-driver aufs --tlsverify --tlscacert /etc/docker/ca.pem --tlscert /etc/docker/server.pem --tlskey /etc/docker/server-key.pem --label provider=generic
```

Docker Machineを作成したローカルPCからは、``docker-machine ls``でマシン一覧を表示し、``eval $(docker-machine env <マシン名>)``で、Dockerの接続先マシンを切り替えることができるようになります。

## Docker Machineに別のクライアントからアクセスする
docker-machineコマンドは、マシンを作成した時に使用したクライアントで利用し、その他のクライアントからDocker Machineにアクセスするには、クライアントのDockerの設定で、参照先が作成したDocker Machineを向くようにします。
以下、参照先変更手順になります。

### Docker Machine設定情報をコピー
Docker Machineを作成すると、``docker-machine create``を実行したPCの下記ディレクトリに、作成されたDocker Machineの各種情報が保存されます。

- ``~/.docker/machine/machines/<マシン名>``

そのうち、Dockerにアクセスするために必要なファイルは

- ``~/.docker/machine/machines/<マシン名>/ca.pem``
- ``~/.docker/machine/machines/<マシン名>/cert.pem``
- ``~/.docker/machine/machines/<マシン名>/key.pem``

の３つで、これを新しいクライアントに、３つが同じディレクトリに置かれるようコピーします。

### Docker環境変数の設定
``docker``コマンドがどのマシンのDockerを見に行くかは、コマンド引数もしくは、環境変数によって設定できます。
ここでは環境変数による設定を紹介します。

下記のようなシェルスクリプトを作り、``source ./change_docker_machine.sh``で環境変数をセットして切り替えます。
ローカルのDockerに戻すには、``source ./change_docker_default.sh``で環境変数を削除します。

```sh:change_docker_machine.sh
#!/bin/bash
export DOCKER_HOST=tcp://<マシンのIPアドレス>:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=<コピーした[ca.pem][cert.pem][key.pem]が置いてあるディレクトリ>
```

```sh:change_docker_default.sh
#!/bin/bash
unset DOCKER_HOST
unset DOCKER_TLS_VERIFY
unset DOCKER_CERT_PATH
```

## 利用例
Dockerを切り替えることができると、ローカルのDockerで作業するのと同じ感覚で、サーバーのDockerが操作できるようになります。

例えば、ローカルで作ったDockerfileをサーバーにアップする際

1. Dockerfileと一連のファイルをサーバーにアップ
1. サーバーにログインして Docker コマンドを実行

といった作業は必要はありません。
単にローカル上で Dockerの 接続先をサーバーに変更して、Docker コマンドを実行するだけでサーバーのデプロイが完了します。

また、docker-compose を使う際も同様で、Docker の接続先をサーバーに変更して、``docker-compose up``コマンドを実行するだけで、サーバーへのデプロイが完了します。
numpy復習ドリルその2

定期的に復習する用に作成。

# アレイの計算
1. （同じサイズの）アレイ同士の四則演算はどのような結果となるか？
1. アレイとスカラー値の四則演算はどのような結果となるか？

## 転置行列
1. 適当な2次元アレイを作成し、転置行列を求めよ
1. 適当な3次元アレイを作成し、transposeを用いて0,1軸、1,2軸を入れ替えよ
1. さらにswapaxesを用いて0,1軸、1,2軸を入れ替えよ

## 乱数
1. 連続一様分布に従う乱数から成る要素10の1次元アレイを作成せよ
1. 正規分布を基にした乱数から成る要素4×4の2次元アレイを作成せよ

## ユニバーサル関数
1. （事前準備）適当なサイズのアレイを作成して下記に答えよ
1. 全要素の平方根を求めよ
1. 全要素の符合を求めよ
1. 全要素のNANか否かを求めよ
1. 最大の要素を求めよ
1. 二つのアレイに対し対応する要素同士の最大値を求めよ

## 数学関数
1. （事前準備）適当なサイズのアレイを作成して下記に答えよ
1. 全要素の和を求めよ
1. 各行毎の和を求めよ
1. 各列毎の和を求めよ
1. 全要素の平均、標準偏差、分散を求めよ
1. 最小値、最大値を求めよ
1. 最小値、最大値を持つ要素のインデックスを求めよ
1. 累積和を求めよ
1. 累積積を求めよ

## 真偽値の関数
1. （事前準備）True,Falseから成る適当なサイズのアレイを作成して下記に答えよ
1. 要素に一つでもTrueがあるかチェックせよ
1. 要素が全てTrueかチェックせよ
Ubuntu MATE 16.04でIPアドレス固定

RaspberryPiでSSHする時に毎回IPが変わってしまうので固定化することに
有線と無線の場合でやり方が違うっぽいのでそれぞれ書いておく

##環境
- Raspberry Pi 3
- Ubuntu MATE 16.04

#有線
IP固定のためには固定するIPアドレスの他に
1. ネットマスク
2. ゲートウェイ
3. DNSサーバー
が必要になります．

※この方法は古いらしいので話半分に

```shell
#ipとネットマスクの確認．
#おそらく，en0のinet addrがipでMaskがネットマスク
$ ifconfig

#ゲートウェイの確認
#さきほどのインターフェースのGatewayを確認
$ route -n

#DNSサーバーの確認
$ cat /etc/resolv.conf
```

```shell
#確認したものを以下に書き込み
sudo vim /etc/network/interfaces

#####################################
auto en０
iface en０ inet static #←dhcpをstaticに変更
	address [設定したいip]
	netmask 255.255.255.0
	gateway 987.654.432.0
	dns-nameservers 123.456.789.0
```

これで再起動しましょう．
#無線
GUIでやるのが正確で楽です．（CLIのやり方を知らないだけだったりする．．）

右上のwi-fiマークをクリックして，一番下の[Edit Connections..]をクリック
固定したいSSIDを選択し，　Edit
![network-manager.png](https://qiita-image-store.s3.amazonaws.com/0/213130/1cb92af2-b1f4-a07b-9d5f-fbeccd4182d5.png)
こんな風に編集して保存→再起動（netmaskはなぜか２４になるんですが．．）

私はこんな感じでできました．
UnityEngine.Object を継承したクラスをインターフェースとして保持していると Null (Fake Null)チェックできない

sumibi-yakitori です。普段は Nintendo Switch でゲーム開発をしています。

さて、
下記のような何らかのインターフェース `IFoo` と `MonoBehaviour` を実装したクラス `FooComponent` があるとして、 

```csharp
public class FooComponent : MonoBehaviour, IFoo { }
```

次のコードのように、インターフェースとして保持していると Fake null がチェックできません。
`==`演算子をオーバーロードしているのは `UnityEngine.Object` だからですかね。

```csharp
var fooComponent = this.GetComponent<FooComponent>();
var foo = (IFoo)fooComponent;

Object.Destroy(fooComponent);

Observable.NextFrame().Subscribe(_ => {
  if (fooComponent == null) {
    Debug.Log("fooComponent は null"); // OK
  }

  if (foo == null) {
    Debug.Log("foo は null "); // NG
  }
}).AddTo(this);
```

この問題は、
`UnityEngine.Object` にキャストした結果をチェックすることで回避することができます。

```csharp
foo as UnityEngine.Object == null;	
```

`foo` はこの場合はローカル変数ですが、
インターフェースとして保持しているのはプロパティやフィールドのことが多いと思うので、
`UnityEngine.Object` を継承していなかった場合のことを考え、
私は次のような条件式でユーティリティメソッド化して使っています。
(コメントで指摘いただいたので更に修正！ありがとうございます)

```csharp
foo == null || (foo is UnityEngine.Object && foo as UnityEngine.Object == null)
```
RaspberryPi3(Stretch)でipを固定してSSHを行う

#はじめに
RaspberryPiを使うたびに、HDMIケーブルでディスプレイに繋ぐって意外と面倒なものです。

RaspberryPi3はwifiモジュールがオンボードです。
SSH接続ができれば電源に繋いでいるだけでRaspberryPiの操作ができるようになります。
机の上がスッキリしますね。

ということで、今回はPC(Windows)からSSH接続をしてみましょう。


#ipアドレスを固定する
SSH接続を行う場合、一般的にRaspberryPi側のipアドレスを固定します。
固定しなければ、毎回ipアドレスが変わってしまうかもしれないので、接続ができなくなります。

1．ipアドレスを調べる
　まずはRaspberryPiがルータから割り振られているipアドレスを調べます。

```terminal
$ sudo ifconfig | grep inet
  inet  192.168.×××.××× netmask 255.255.×××.××× broadcast 192.168.×××.×××
  inet6 ××××::××××:××××:××××:××××  prefixlen ××  scopeid 0x××<link>
  inet ×××.×.×.×  netmask ×××.×.×.×
  inet6 ::×  prefixlen ×××  scopeid 0x××<host>
```
　※「×」は各環境によって数字が異なります。
  　以上の様に表示されたと思います。

　もしくは下記の様にipアドレスを調べます

```terminal
$ ip route
default via 192.168.0.1 dev wlan0 src 192.168.0.15 metric 303
192.168.0.0/24 dev waln0 proto kernel scope link src 192.168.0.15 metric 303
```

　ルータのipアドレスが「192.168.0.1」であり、DNSから振られているラズパイのipアドレスが「192.168.0.16」であることが分かりました。
　これらの情報に基づき、下記のファイルを編集します。

2．ipアドレスを固定する

2、3年前の記事を見るとよく

```terminal
/etc/network/interfaces
```

にip固定を記述しているものを見かけます。
現在では/etc/network/interfacesにアクセスすると以下の様な記述があります。

```
#Please note that this file is written to be used with dhcpcd
#For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
```

現在では次のファイルに記述するようになっています。

```terminal
/etc/dhcpcd.conf
```

では、ipアドレスを固定します。

```terminal
$ sudo vim /etc/dhcpcd.conf
```
末尾に以下の記述を追加します。

```terminal
interface wlan0
static ip_address=192.168.0.15/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1
```
routers、domain_name_serverは基本的にルータのipアドレスを指定します。

#SHHを有効化する
ますは設定画面を開きます。

```terminal
$ sudo raspi-config
```

「5 Interfacing Options」を選択します。
矢印キーで移動し、Enterキーで選択できます。
![2018-05-29-061743_655x390_scrot.png](https://qiita-image-store.s3.amazonaws.com/0/161128/13a74f04-d164-9d74-6031-ea9eff703b98.png)

「P2 SSH」を選択します。
![2018-05-29-061752_655x390_scrot.png](https://qiita-image-store.s3.amazonaws.com/0/161128/5224b360-15f1-ee22-d461-1ae60b8f086d.png)

＜Yes＞を選択します。
![2018-05-29-074226_655x390_scrot.png](https://qiita-image-store.s3.amazonaws.com/0/161128/316228ad-c0c3-cc4a-ee5f-13ed3cc6f2bf.png)


SSHが有効化されました。
![2018-05-29-074238_655x390_scrot.png](https://qiita-image-store.s3.amazonaws.com/0/161128/20506490-9034-acea-661d-c7160cb8df26.png)


#SSHで接続する
###1. TeraTermをインストールする
PC(Windows)にTera Termをインストールします。
https://ja.osdn.net/projects/ttssh2/releases/

この[リンク](https://ja.osdn.net/projects/ttssh2/downloads/69111/teraterm-4.98.exe/)をクリックすると最新版のダウンロードが始まります。
※2018年5月29日現在の最新版は4.98です。

ダウンローダの手順に従ってインストールを行ってください。

###2. SSH接続を行う
TeraTermを起動します。
ホストには先ほど固定したipアドレスを入力します。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/161128/4f026db7-c3a4-efc6-14a9-0a7805e96774.png)

RaspberryPiのユーザ名とパスワードを入力し[OK]をクリックします。
特に変更していなければ、ユーザ名は「pi」、パスワードは「raspberry」です。
![無題1.png](https://qiita-image-store.s3.amazonaws.com/0/161128/e9826887-bafe-e491-554c-233f7dd327e4.png)


SSHが成功しました。
![無題3.png](https://qiita-image-store.s3.amazonaws.com/0/161128/1e41e941-3f07-dfc3-d75f-591e4cfaf401.png)

#おわりに
以上でSSH接続が完了しました。
次回からはRaspberryPiをディスプレイに接続する必要が無くなりましたので、
机のスペースを有効活用できるかと思います。
なんちゃってビジュアルリアルタイム監視


単に、gnuplot のグラフをターミナルで動的に閲覧するだけの古いやり方。

- gnuplot
- topless

今回は sar [^1]で例を書く。

[^1]: CentOS6.8 で。 OS X の sar は別挙動。

- sar

## バックグラウンドジョブ
cron なんかで、数値のログを取るジョブを走らせる。
sar が単純なので。

```
$ pwd 
/PATH/TO/FOO
$ LANG=C sar 1 > sar.txt &
```


## グラフ作成スクリプト

gnuplot でターミナルにグラフ出力する。

$ti とかは、必要あれば正しい日時に[^2]。

[^2]: 一応、gnuplot のタイムスタンプに変換はしてる。最近のgnuplotだとUNIXタイムと同じになってるから注意


```shell-session:
tail -200 sar.txt | while read -a ARR ; do
    ti="2018-01-01 ${ARR[0]}"
    d=$(( $(date +%s -d"$ti" ) -  946652400)) #
    echo $d ${ARR[2]}
done  > /tmp/tmp.txt
gnuplot <<'EOF'
#!/usr/bin/env gnuplot
set terminal dumb
set title 'CPU'
set xdata time
set timefmt "%s"
set format x "%M:%S"
plot '/tmp/tmp.txt'  u ($1):($2) notitle w l
EOF
rm /tmp/tmp.txt
```

これを実行すれば、

```shell-session:
$ bash ./graph.sh
gnuplot> #!/usr/bin/env gnuplot
gnuplot> set terminal dumb
Terminal type set to 'dumb'
Options are 'feed  79 24'
gnuplot> set title 'CPU'
gnuplot> set xdata time
gnuplot> set timefmt "%s"
gnuplot> set format x "%M:%S"
gnuplot> plot 'tmp.txt'  u ($1):($2) notitle w l
                                         CPU

    2.5 ++-+--+--+-+--+--+--+--+--+-+--+--+--+--+--+-+--+--+--+--+--+-+--+-++
        +        +       +        +       +        +       + *      +       +
        |                                                    *              |
        |                                                    *              |
      2 ++                                       *           *             ++
        |                                        *           *              |
        |                                        *           *              |
        |                                        *           *              |
    1.5 ++                                   *   *           *             ++
        |   *                                *   *           *              |
        |   *                                *   *           *   *          |
      1 ++  *                                *   **   *     **   *  *      ++
        |   *                                *   **   *     **   *  *       |
        |   *                                *   ** * *   * **   *  *       |
        |    *                           *  **   ** * *   * **   *  *       |
    0.5 ++   *                           *  **   ** * **  * **   *  *      ++
        |    *                           *  **   ** * **  * **   *  *       |
        |    *                           *  **   ** * **  * **   *  *       |
        +    *   +       +        +     **+ **   **+****  *+**   *  *       +
      0 ++-+-*********************************************************+--+-++
      44:30    45:00   45:30    46:00   46:30    47:00   47:30    48:00   48:30

gnuplot>
```


## ビジュアルリアルタイム監視

あとは topless で監視するだけ。

```shell-session:
$ topless -s 10 'bash ./graph.sh | grep "^ "'
```
ansible-playbook で複数コマンド個別実行の結果を比較的スマートに表示する。


ansible 。ようやく手を出した。

ansible-playbook の場合、対象サーバの情報を抜き出して、表示させたいだけなのに、with_items で shell を
ループさせただけで、debug 時に他の雑多な情報に埋もれてしまう。

それだったら、シェルで for して、ansible をワンライナで叩いた方が見やすい。

、、、それで満足してたら進歩がないので、方法を探す。

## 実行

で、ぐぐったが、いい方法に当たらない、、、

仕方ないので、試行錯誤した挙句の果てが↓コレ。

```YAML:test.yml
- hosts: root
  become: yes
  tasks:
    - shell: "{{ item }}"
      with_items:
        - 'echo first'
        - 'echo second'
        - 'echo third'
      register: result
    - debug: var="result.results.{{item}}.stdout_lines"
      with_sequence: start=0 end=2
```

with_items で回した場合の register は、変数名.results に蓄積されてく。

その内容には、配列っぽく 0, 1, 2 のインデクスでアクセス出来る。で、その配下に、 stdout_lines とか stderr_lines とかある訳で。

と言うことで、 index で回して、標準出力だけを表示させる。


```shell-session:
$ ansible-playbook -i hosts test.yml

PLAY [root] ********************************************************************************************

TASK [Gathering Facts] *********************************************************************************
ok: [GUEST]

TASK [command] *****************************************************************************************
changed: [GUEST] => (item=echo first)
changed: [GUEST] => (item=echo second)
changed: [GUEST] => (item=echo third)

TASK [debug] *******************************************************************************************
ok: [GUEST] => (item=0) => {
    "item": 0,
    "result.results.0.stdout_lines": [
        "first"
    ]
}
ok: [GUEST] => (item=1) => {
    "item": 1,
    "result.results.1.stdout_lines": [
        "second"
    ]
}
ok: [GUEST] => (item=2) => {
    "item": 2,
    "result.results.2.stdout_lines": [
        "third"
    ]
}

PLAY RECAP *********************************************************************************************
GUEST                  : ok=3    changed=1    unreachable=0    failed=0

```

実用では、 name とかから、何のコマンドを実行したかを切り出すのは結構面倒なので、素直に - shell: 'echo WHAT_TO_DO ; WHAT_TO_DO' でお茶を濁す。


## 結果の加工

複数サーバを対象に実行した場合は、結果が入り乱れてしまうので、DEBUG の部分だけログから切り出して、

```shell-session:
$ perl -F'(?=2018)' -0777lane 'print for map{ $_->[0] } sort { $a->[2] <=> $b->[2] or $a->[1] cmp $b->[1] } map { [ $_, (/\[(.*?)\].*?item=(\d+)/ )[0,1] ] } @F ' TEXT
```

でサクッと index 順 => サーバ順に並べなおして確認する、、、[^1]

[^1]: もちろん、2018 が、stdout とかに含まれてたら、使えない。標準出力の方は、またちょっと違う。-F'(?=ok:)' に差し替えれば、動くと思う。やってないけど。
インスタンスは生きているのに ElasticBeanstalk の監視から外れたので復帰させた

チカクにはElasticBeanstalkで管理しているAmazon Linuxのインスタンスがあります。
インスタンスは生きているのに監視から外れてコンソール上のヘルスがWARNになったことがありました。

インスタンスを再起動しても良かったのですが、対象のインスタンスで`healthd`というプロセスがCPU使用率が高い状態でしたので、以下のコマンドを実行することでプロセスを再起動したところ、CPU使用率が下がり、AWSのコンソール上も復帰しました。

```shell
sudo kill $(ps -ef | grep "\[healthd\]" | awk '{ print $2 }')
```

これでも再起動しない場合もあるので、その際は `kill`コマンドに`-9`オプションをつけるとより確実です。
【Swift4.0】Thread 1:signal SIGABRT　エラー発生時の解決方法

この記事ではSwift4、Xcode Ver9.3を使っています。

XcodeのiOS simulatorでTread 1:signal SIGABRTが出てアプリが立ち上がらないエラーに直面しました。
このエラーの意味は、「Signal(=ここでは「やりとり」みたいな意味)がAbortする(=ここでは「中断する)みたいな意味）と理解しておくとわかりやすいかもしれません。

原因をネットで検索すると色々出てきました。主要なものとしては、

　・StoryBoardでOutlet接続したのに、そのOutletが上手くリンクしていない
　・配列で存在しない添字にアクセスしている
　・オブジェクトがnilになっている
　・コード修正前のキャッシュが残っている

などが書かれていましたが、どれを試してみてもThread 1:signal SIGABRTエラーは消えず。。
なので、デバックエリアにブレークポイントを置きながら、時間をかけて原因を調べてみました。

結果として、エラーの原因は「クラスにモジュール名を指定し忘れていたこと」で「Outlet接続が上手くリンクされていなかった」みたいです。
Xcode上でStoryBoardを選択→対象のViewControllerを選択→show the identify inspectorを選択→ClassとModuleを正しく入力→Outlet接続を一度切り、再接続することで、Thread 1:signal SIGABRTエラーは消えました。

デバックエリアをみてもエラーの原因が即座にわからないので怖くなりますよね。
今回は一例として、こんな方法で治るよ！ということをご紹介しました。
packageを使わないでやってみた(2次元ニュートンラフソン)

```{r}
#2dim-newton raphson
library(dplyr)
f<-deriv(~x^2/16+y^2/9-1,c("x","y"),function(x,y){})
g<-deriv(~x^2-y,c("x","y"),function(x,y){})
A=t(t(rep(9,2)))
times=100
val_f=val_g=df=dg=0
for(j in 1:times){
  a=A[1];b=A[2]
  df=attr(f(a,b),"gradient")
  dg=attr(g(a,b),"gradient")
  H=matrix(c(df,dg),ncol=2,nrow=2)
  A=A-((det(H)^(-1))*matrix(c(dg[1,2],-dg[1,1],-df[1,2],df[1,1]),ncol=2,nrow=2))%*%c(f(a,b)[1],g(a,b)[1])
}

A
```
```{r}

#多次元勾配上昇法

library(dplyr)

d=3

f=function(x){
  
return(exp(-(x[1]-2)^2)+exp(-(x[2]-1)^2)+exp(-(x[3]-3)^2))
  
}


ite=100000

value=rep(0.1,d)

eta=0.01;h=0.01

for(j in 1:ite){
  
for(i in 1:d){
  
vec=rep(0,d);vec[i]=vec[i]+h  
  
value[i]=value[i]+eta*(f(value+vec)-f(value))/h  
  
}  
  
#print(value)  
    
}

print(value) 

```


```{r}

#Levenberg-Marquardt method

library(dplyr)

data=data.frame(num=1:20,y=c(0.20, 0.10, 0.49, 0.26, 0.92, 0.95, 0.18, 0.19, 0.44, 0.79, 0.61, 0.41, 0.49, 0.34, 0.62, 0.99, 0.38, 0.22,0.71,0.40),x1=c(84,87,86,85,82,87,92,94,88,84.9,78,90,88,87,82,84,86,83,85.2,82),x2=c(61,55.5,57,57,50,50,66.5,65,60.5,49.5,49.5,61,59.5,58.4,53.5,54,60,58.8,54,56),x3=c(24.5,24,23,22.5,22,24,25,26,25,24,23,21,26,25.5,24,23,24,24,24,22))

X=as.matrix(data[,colnames(data) %in% c("x1","x2")])/1000

Y=as.numeric(data$y)

n=nrow(data)

l1=function(x,y,a){
  
return((y-sum(exp(x*a))))  
  
}

l2=function(x,y,a){
  
return(sqrt(abs(y-sum(x*a))))  
  
} 

a=rep(1,nrow(X))





ite=10000

h=0.001;mu=10000

for(j in 1:ite){
  
 
  
a_pre=a  
  
df_vec=c();dl_vec=array(0,dim=c(nrow(X),ncol(X)))

ls=c()

for(i in 1:length(Y)){
df=l1(X[i,],Y[i],a[i])*(l1(X[i,]+h,Y[i],a[i])-l1(X[i,],Y[i],a[i]))/h+l2(X[i,],Y[i],a[i])*(l2(X[i,]+h,Y[i],a[i])-l2(X[i,],Y[i],a[i]))/h  

dl1=(l1(X[i,]+h,Y[i],a[i])-l1(X[i,],Y[i],a[i]))/h
dl2=(l2(X[i,]+h,Y[i],a[i])-l2(X[i,],Y[i],a[i]))/h

ls=c(ls,l1(X[i,],Y[i],a[i])+l2(X[i,],Y[i],a[i]))

dl_vec[i,]=c(dl1,dl2)
 
df_vec=c(df_vec,df)
         
}

J=dl_vec

ds=solve(J%*%t(J)+diag(mu,n))%*%(-df_vec)

a=a+ds

#print(sum(abs(a-a_pre)))

print(sum(ls^2))

}

```
Pythonで機械学習の勉強始めたら「could not find or load the Qt platform plugin windows」でつまった

Pythonを導入し、意気揚々と機械学習の学習を始めたらグラフを描写するにあたり
「could not find or load the Qt platform plugin windows」
というエラーメッセージがでてうまくいかない。

調べてみると、以下のような記事が。

https://stackoverflow.com/questions/41994485/error-could-not-find-or-load-the-qt-platform-plugin-windows-while-using-matplo

記事の通りにシステム環境変数を設定後、
Pycharmを再起動したら無事グラフ描写された。

パス　ローカル環境\Anaconda3\Library\plugins
環境変数　QT_PLUGIN_PATH
ブロックチェーン-Ethereumでスマートコントラクト開発入門編

#スマートコントラクトとは？
事前に定義されたプログラム通りに、条件を満たした時に自動で契約を執行することを**スマートコントラクト**と言います。

例えば、電子マネーのオートチャージのように、　残高が3,000円を下回ったら、3,000円チャージする、のようなものです。

#イーサリアム
イーサリアムとはブロックチェーンのネットワーク上でアプリケーションを実行できるプラットフォームです。
ETHと呼ばれる仮想通貨を消費して、プログラムの実行が可能です。

[ブロックチェーンについてはこちらのブログを参照](https://diffeasy.com/posts/skill/1831)

#Solidityとは？
Solidityとはイーサリアムプラットフォームスマートコントラクトを開発するためのJavaScriptライクな開発言語です。
ブラウザベースの統合開発環境[Remix](https://remix.ethereum.org/)を利用すると、簡単に開発をスタートできます。

<img width="1439" alt="Remix" src="https://qiita-image-store.s3.amazonaws.com/0/3003/29a4583d-7f13-eac6-5637-49db0335c192.png">

#Getter Setterのサンプル
[Remix](https://remix.ethereum.org/)にアクセスして、画面左上の＋ボタンから新規ファイルを作成します。

### プログラムの作成
今回は簡単なGetterSetterを作成します。
IDEで以下の内容を記述します。

contractValueにsetValueで値をセットし、getValueで値を取得します。

```sample.sol
// バージョンプラグマの指定
pragma solidity ^0.4.0;

// サンプルコントラクトの宣言
contract Sample {
    // サンプル変数の宣言
    string contractValue;
    
    // サンプル変数に値をセット
    function setValue(string localValue) {
        contractValue =localValue;
    }
    
    // サンプル変数の値を取得
    function getValue() constant returns (string) {
        return contractValue;
    }
}
```

### プログラムのコンパイルと、実行の準備
画面右側「Compile」タブの「Start to Compile」ボタンをクリックすると、コンパイルされます。

コンパイルが正常に終わったら、「Run」タブに切り替えます。

<img width="390" alt="スクリーンショット 2018-05-30 18.56.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/3003/6410aea1-1429-7303-c7f4-6957b9ccc43e.png">

Environmentはプログラムを実行する環境です。
JavaScriptVMを選択します。

Accountは実行するアカウントです。
複数存在しますが、今回はどれでも良いです。

イーサリアムでは、プログラムを実行するために　ETHという仮想通貨を消費します。
アカウントIDの右側に(100ether)とありますが、これがアカウントが保有しているETHです。

### プログラムの実行
それでは、先ほどのプログラムを実行してみましょう！
<img width="389" alt="スクリーンショット 2018-05-30 19.03.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/3003/526dad60-25fd-4f12-8b26-df074e608926.png">

先ほど作成した「Sample」を選択して「Deploy」をクリックします。
すると、アカウントID右側のetherが減ります。

イサーリアムではコントラクトに対してデータを送信する際、「Gas」と呼ばれるコストを消費します。


<img width="389" alt="スクリーンショット 2018-05-30 19.10.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/3003/6ca905ab-adc6-0a25-68b6-9e25be5b421d.png">

setValueのlocalValueに「"ほげほげ"」を入力して、「transact」をクリックします。
<img width="368" alt="スクリーンショット 2018-05-30 19.11.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/3003/cc728dd1-2296-0553-28a0-960db59a408e.png">
すると、またGasが消費されたのがわかります。

次にgetValueを実行します。
getValueをクリックすると、setValueでセットした値が表示されます。
<img width="372" alt="スクリーンショット 2018-05-30 19.12.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/3003/24e646cd-8fda-3a97-4e8a-b8baf7a4af03.png">
setValueの際はGasが消費されましたが、getValueの際はコントラクトに対してデータを送信しないので、Gasは消費されません。
c# 単体で　画像縮小（Bilinear）


C#単体で、画像を縮小する

```cs:syuku01.cs
//c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /target:winexe syuku01.cs

using System.Drawing;

public class syuku01
{
 public static void Main(string[] args)
 {
	if(args.Length==2){
		string path1;//in file name
		string path2;//out file name

		path1 = @".\" + args[0];
		path2 = @".\" + args[1];

		int rt =3;
	
		Bitmap image1;
		image1 = new Bitmap(path1, true);
	
		Bitmap canvas = new Bitmap((int)image1.Width/rt, (int)image1.Height/rt);
		Graphics g = Graphics.FromImage(canvas);
	
		g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
	
		g.DrawImage(image1, 0, 0, (int)image1.Width/rt, (int)image1.Height/rt);
	
		canvas.Save(path2, System.Drawing.Imaging.ImageFormat.Jpeg);
	}
 }

}
```
他アプリにPermissionダイアログを表示させずに権限を付与する方法

**System App のみ**

### 必要Persmittion

    <uses-permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS" />
    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
    <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
    <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />

あたりを付与する側に付けておく

### 実コード
Androidのソースの `com.android.packageinstaller.permission.ui.handheld.AppPermissionsFragment`あたりを見るのが一番早い

`com.android.packageinstaller.permission.model.AppPermissionGroup`が実際に権限を付与したりはずしたりしてて、その中の`grantRuntimePermissions`メソッド参照
こいつの実体は

```AppPermissionGroup.java
mPackageManager.updatePermissionFlags(permission.getName(),
    mPackageInfo.packageName,
    PackageManager.FLAG_PERMISSION_USER_SET
    | PackageManager.FLAG_PERMISSION_USER_FIXED,
    0, mUserHandle);
```

上記のメソッドを呼ぶところが本丸
PackageManagerの`updatePermissionFlags`というそのまんまな名前のメソッドにより設定できる

注意点は上記で出てきてる`permission`は`java.security`のPermissionクラスではなく、`com.android.packageinstaller.permission.model`のPermissionクラスなので、コードをコピペしてとりあえず動かそうってときに悲しくなったりする
【LINE BOT】仮想通貨BOTをつくってみた【Python】

##**はじめに**
プログラミングがまったく初心者の記録的投稿
またこの記事がほかの初心者の方のお役に立てれば幸いです

今回は、[前回](https://qiita.com/cachio_qiita/items/d96e67ebfee5e1c8774f)のPythonの環境構築でつくった仮想環境をさっそく用いて、
今流行り(?)の仮想通貨「ビットコイン」の価格を教えてくれるLINE BOTをつくりました

####**LINE BOTの紹介**
今回作成したのは、**bitflyer**, **zaif** など仮想通貨取引所の名前を送ると、
そこで取引されているビットコインの現在取引額を日本円でかえしてくるLINE BOTです
自身のLINEへの追加方法も以下に記載しています

####**使い方**
対応している取引所は

- bitFlyer
- Zaif
- ~~Coincheck~~(送ってみると...)

下図のような感じで`bitflyer`, `zaif`と送信すると価格がかえってきます

<img width="320" alt="fullsizeoutput_2c3.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/243693/08bab6d0-c1ea-2772-f15d-e283bbfd499d.jpeg">

ちなみに`ビットフライヤー`, `ざいふ`などひらがな、カタカナでも大丈夫です

<img width="320" alt="fullsizeoutput_2c6.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/243693/8a9e67ae-e874-5445-320c-16eca3ac3ebe.jpeg">




####**LINE 友だち追加用 QRコード**

LINE起動→友だち追加→QRコード
からコチラのQRコードを読み取ってBOTを友だちに追加することが出来ます

![fullsizeoutput_2c0.jpeg](https://qiita-image-store.s3.amazonaws.com/0/243693/d1b9fcc0-3657-cb65-e701-c384a3ab0734.jpeg)

もしくは、以下の友だち追加ボタンからでもOK

<a href="https://line.me/R/ti/p/%40cvl6978k"><img height="36" border="0" alt="友だち追加" src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png"></a>

###**技術情報・ソースコード**
GitHubに公開してます
[cachio/cachio-coin](https://github.com/cachio/cachio-coin)
開発工程は[コチラ](https://qiita.com/cachio_qiita/items/2ea176ba60f29580e7f4)で紹介してます


##**おわりに**
今回のBOTは、LINEの公式サンプルボットのコード(オウム返しBOT)に各取引所のAPIを組み込んだもので、プロなら完成までたったの数十分もかからない単純なものです
ただ右も左もわからない初心者は、ここQiitaや[teratail](https://teratail.com/)などで関連するものをあれやこれやと調べたり質問したりと試行錯誤しているとだいぶ日数がかかってしまいました...

ビットコインの価格をかえしてくれるだけで実用性はほぼ無いですが、
はじめての自作プロダクト(もどき？)が実現できたので、つぎのプログラミング創作活動への良いモチベーションになりました
TouchDesigner での条件分岐(Expression CHOP)

TouchDesigner でCHOPの値を条件分岐させる方法を紹介していきたいと思います。

##Expression CHOP
入力に対して条件と返り値を指定できるオペレータです。

###例
![スクリーンショット 2018-05-30 18.37.13.png](https://qiita-image-store.s3.amazonaws.com/0/175399/90a97640-b049-6600-71fa-7315d86ba9ce.png)

![スクリーンショット 2018-05-30 18.37.28.png](https://qiita-image-store.s3.amazonaws.com/0/175399/1f7f910a-f6f4-e77e-8c97-8431f48f396b.png)
デフォルトでは入力値をそのまま返すようになっています。

Expression CHOP のパラメータのExprのExpresion1を見ると `me.inputVal`となっているため入力値がそのまま返ってきます
ここでExpression1を`me.inputVal > 0.5`にすると入力の時にTrue(1)を返す条件式を記述することができます
![expression.gif](https://qiita-image-store.s3.amazonaws.com/0/175399/dc4030b8-3884-41c2-62b5-ed4a918e1dac.gif)

またifelse文を記述することができます
文法:`条件一致時返り値 if 条件式 else 条件不一致時返り値`
例えば入力値が0.5以上の場合は入力値、0.5未満の場合は0を返す場合
`me.inputVal if me.inputVal >= 0.5 else 0`となります
![expression2.gif](https://qiita-image-store.s3.amazonaws.com/0/175399/7a06d5f0-95f0-76de-bb30-9944987fc972.gif)

<a href="https://qiita.com/joe_ohara/items/82f5de39ff82873e994b">TouchDesigner での論理演算</a>の記事と組み合わせることでより複雑な処理を行うことができるでしょう！！
RxJavaでbufferオペレーターを使ったユニットテストでハマった

この記事は雑です。

## 結論

`RxJavaPlugins.set***SchedulerHandler` に `trampoline` を設定していたけど、 `setIoSchedulerHandler` だけにした。

```kotlin
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
```

## なぜ

こんな感じのTestRuleを書いていたのだけど、

```kotlin
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
RxJavaPlugins.setComputationSchedulerHandler { Schedulers.trampoline() }
...
```

テスト対象のコードに、 `buffer` オペレーターがあると、bufferオペレーターは内部的に `computation` スケジューラーを利用しているので、 `trampoline` スケジューラーに上書きしてしまうことで無限に待ち続けてしまって、テストが終わらなくなる。

```kotlin
@Test
fun testBuffer() {
    val subject = PublishSubject.create<Int>()
    val testObserver = subject
        .buffer(1, TimeUnit.SECONDS)
        .filter { it.isNotEmpty() }
        .test()

    subject.onNext(1)
    subject.onNext(2)

    testObserver.await(2, TimeUnit.SECONDS)
    testObserver.assertValues(listOf(1, 2))
}
```
とりあえず使えりゃ良いんだよ使えりゃという雑なpythonログ出力実装メモ

# どこもかしこも
ログの階層構造の説明だの、複数ファイルで出力するときの方法だのなんだのと。
説明が冗長……とは言いませんが、詳しすぎて初心者にはきつかったです。

いや、**ログのレベルの概念**は理解してますねん。

**pythonでのログの書き方を知りたいだけですねん。**

そういう気持ちを形にしました。


# 最低限

１ファイルで完結するpythonのプログラムでログを吐かせたいだけならこれでOK。

```python:
import logging

# ログ定義
logger = logging.getLogger(__name__) # %(name)sになる
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 標準出力
streamHandler = logging.StreamHandler()
streamHandler.setFormatter(formatter)

# ファイル出力
fileHandler = logging.FileHandler('./log/hogehoge.log')
fileHandler.setFormatter(formatter)

# ロガーにハンドラーを追加
logger.addHandler(streamHandler)
logger.addHandler(fileHandler)

# ログ出力時
logger.info("info log message.")
logger.debug("debug log message.")

```

これで標準出力とファイルの両方にログが記録されていく。
出力先ごとにログのレベルを変えたい場合は個別のハンドラに`fileHandler.setLevel(logging.INFO)`とかすれば変わる。

asctimeはローカルの時間になるっぽい？　です。
cloud9が何故か西アメリカになっていたのでそのせいかな……設定のAWS Settingsを変えたら変わるかと思ったんですが変わりませんで。
設定の再読込が必要なのかなー……と思いつつ、あんまり不便ではないので放置しています。


## メール出力
最低限＋αでメールについても載せておきます（自分が使いたいので……）

```python:
# メール出力
import logging.handlers

emailHandler = logging.handlers.SMTPHandler(
    mailhost='smtp.mailtrap.io',
    fromaddr='FROMアドレス',
    toaddrs=['TOアドレス'],
    subject='メールタイトル',
    credentials=('user', 'password')
    )

emailHandler.setFormatter(formatter)

logger.addHandler(emailHandler)


```

- [16.8. logging.handlers — ロギングハンドラ — Python 3.6.5 ドキュメント](https://docs.python.jp/3/library/logging.handlers.html#smtphandler)
- [Python logging 各種出力ハンドラーの使い方について - Symfoware](https://symfoware.blog.fc2.com/blog-entry-885.html)

# 参考資料

- [pythonのロギングに関するメモ · JoeMPhilips](http://joemphilips.com/post/python_logging/)
- [【Python入門】loggingモジュールでログを表示してみよう！ | 侍エンジニア塾ブログ | プログラミング入門者向け学習情報サイト](https://www.sejuku.net/blog/23149)

ひとつめが割と求めるものに近いざっくりした内容。
ふたつめがもう少し詳しいので、なんとなく動きを確認したら読んでみると良いかも。

## ちゃんみおポイント
ひとつめの方で、若干 **ぜんぜん違うじゃん！！** となったのでメモ。~~若干ぜんぜんとは~~

### importが紛らわしい
ベストプラクティス、として紹介されているコードに`from logging import getLogger,StreamHandler,DEBUG`とか書いてあるのだけれど、結局あとでFormatterとか使うときに修正するので最初から`import logging`でいいのでは……となりました。


### コードが違う

```python:お手本
formatter = logging.Formatter('%(asctime)s - %(name) - %(Levelname)s - %(message)s') #%()内に入る属性はLogRecordと呼ばれる

# 結果
# 2018-05-30 08:27:48,918 - %(levelname)s - Min:811625.0,Target:807566.875,Current:816000.0

```

```python:修正
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #%()内に入る属性はLogRecordと呼ばれる

# 結果
# 2018-05-30 08:34:31,068 - __main__ - INFO - Min:812945.0,Target:808880.275,Current:817105.0

```

**「$(name) - 」が読み飛ばされてるっぽい**のが謎すぎて焦りました。

# 追記
- [ログ出力のための print と import logging はやめてほしい - Qiita](https://qiita.com/amedama/items/b856b2f30c2f38665701)

ログについていろいろ書かれていて勉強になりました。

`import logging`でいいのでは、とか言ってごめんな……
【Oculus Go×Unity】JDKの設定にハマった【mac】

Oculus Goの環境構築中にJDKの設定にハマったので、記録を残します
さまざまな経緯はあったのですが、結論から述べます

## 結論
    /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/

- ただなぜこのパスなのかもよくわからないけど、うまくいっている

## UnityでAndroidの設定をする
- Unity/Preferences/External Tools にAndroidの項目があり、SDK・JDK・NDKを設定する箇所がある
    - <img width="350" alt="スクリーンショット 2018-05-30 18.31.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/77327/61f82197-2487-7957-b909-405c48d8f779.png">
- ↑で出てこない人は File/Build Settings でPlatformにAndroidを選択し、AndroidStudioを入れたり、Androidを動かせるようにUnityの設定変更を行う
- Android StudioはSDKとかJDKのバージョン変更の時くらいにしか使わないらしいが、簡単に入りそうだったので、とりあえず入れてみた
- それでもAndroidの項目が出ない人はUnityを再起動すると設定できるようになっている
- （Unityで何かうまくいかないなぁという時、割と再起動が有効な手段だったりする）


## SDKはすんなり見つかる
- Finderからすんなりたどり着けた

        /Users/kana/Library/Android/sdk

- Android Studioからも確認できる
    - 起動時にConfigure/SDK Manager からAndroid SDK Locationがわかる

## JDKが見当たらない
- 片っ端からパスを入れまくった
    - システム環境設定のJavaからJavaコントロール・パネルを開き、Javaタブでパスを確認
    - ターミナルで'which java'をしてパスを確認
    - Android StudiodでFile/Project Structure…/SDK Location/JDK locationでパスを確認
    - /System/Library/Java/JavaVirtualMachines/
    - /Library/Java/JavaVirtualMachines/
    - /Users/$USER/Library/Java/JavaVirtualMachines
    - ・・・
    - よって、Unityでbuildが通らない

## 解決方法
- JDKの設定を空欄にして、build
- 勝手にJDKのパスが指定されて、build成功！

## 感想
- 色々調べたのに、最後はやけくそで空欄build実行でうまくいくという結末に・・切なくなった
javascriptで出産予定日から妊娠日数・妊娠週数・妊娠月数を求める。

とりあえずこんな感じでしょうーか。

<p data-height="265" data-theme-id="0" data-slug-hash="qKEExM" data-default-tab="js,result" data-user="blue-ossan" data-embed-version="2" data-pen-title="出産予定日から妊娠週数・月数・日数計算機" class="codepen">See the Pen <a href="https://codepen.io/blue-ossan/pen/qKEExM/">出産予定日から妊娠週数・月数・日数計算機</a> by Satoshi Oikawa (<a href="https://codepen.io/blue-ossan">@blue-ossan</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
Ubuntu 18.4 LTSでCentOSのインストールDVDを焼いてみるーーとりあえず、Cent OSでLinuxカーネルのコンパイルをしたい

Linuxカーネルをコンパイルしてみたいと思いましたが、UbuntuではLinuxカーネルのコンパイルは難しいようなので、Cent OSをインストールして、Linuxカーネルをコンパイルしようと思いました。
で、ノートPCでLinuxカーネルをコンパイルすると熱が篭ってPCがやられるらしいので、ジャンクワールドでデスクトップPCを買って、CentOSをインストールしてみようかと思います。
とりあえず、今持っているUbuntuで、Cent OS 7のインストールDVDを焼こうかと思います。

https://www.centos.org/download/

上のサイトから、DVD isoをダウンロードしました。
Ubuntuでは、GUIツールを使えば、DVDは焼けるはずなのですが、何故か僕の場合できなかったので、コマンドラインで焼いてみます。

http://blog.amedama.jp/entry/2017/03/10/211513

上のサイト様を参考にさせていただきました。

環境構成は以下の通り

```
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04 LTS"
```

```
$ uname -r
4.15.0-22-generic
```

今回使った環境では、メディアに書き込むためのデバイスは /dev/sr0 で認識されているようです。

```
$ ls /dev/sr0
/dev/sr0
```
以下のファイル形式

```
$ file CentOS-7-x86_64-DVD-1804.iso
CentOS-7-x86_64-DVD-1804.iso: DOS/MBR boot sector; partition 2 : ID=0xef, start-CHS (0x3ff,254,63), end-CHS (0x3ff,254,63), startsector 2368, 17976 sectors
```
書き込むのに使うツールの入ったパッケージをインストールします。

```
$sudo apt-get -y install growisofs
```

書き込みは growisofs コマンドでやります。 引数として、デバイスと書き込む ISO ファイルを指定してやる。

```
$ growisofs -Z <dev>=<isofile>
```

今回の例ではこんな感じ。もちろん、カレントフォルダに、isoファイルがあることが必須

```
$ growisofs -Z /dev/sr0=CentOS-7-x86_64-DVD-1804.iso
```
エンターを押すと、DVDが回る音がして、書き込みプロセスが始まります。

```
$ growisofs -Z /dev/sr0=CentOS-7-x86_64-DVD-1804.iso
Executing 'builtin_dd if=CentOS-7-x86_64-DVD-1804.iso of=/dev/sr0 obs=32k seek=0'
/dev/sr0: "Current Write Speed" is 16.4x1352KBps.
    2785280/4470079488 ( 0.1%) @0.6x, remaining 133:39 RBU 100.0% UBU   0.0%
   29491200/4470079488 ( 0.7%) @5.8x, remaining 22:35 RBU 100.0% UBU   0.0%
   57311232/4470079488 ( 1.3%) @6.0x, remaining 15:23 RBU 100.0% UBU   0.0%
   85131264/4470079488 ( 1.9%) @6.0x, remaining 12:52 RBU 100.0% UBU   0.0%
  112918528/4470079488 ( 2.5%) @6.0x, remaining 12:13 RBU 100.0% UBU   0.0%
  140738560/4470079488 ( 3.1%) @6.0x, remaining 11:16 RBU 100.0% UBU   0.0%
  168558592/4470079488 ( 3.8%) @6.0x, remaining 10:37 RBU 100.0% UBU   0.0%
  196378624/4470079488 ( 4.4%) @6.0x, remaining 10:31 RBU  99.9% UBU   0.0%
  224165888/4470079488 ( 5.0%) @6.0x, remaining 10:06 RBU 100.0% UBU   0.0%
(このあとも続く)
```
しばらく待ってやれば、書き込みプロセスは終わります。
次回は、Linuxカーネルのコンパイルから始まります。
Laravelが実際に依存オブジェクト注入しているのはどこ？？？ - Laravelコードリーティング

# 前置き

Laravel5.6のコードを読んでいきます。
DIだとか依存性注入だとかいうけど、実際にはどこで注入してんだよ！ってのが気になったので調べました。

# Let's コードリーディング!!!

はじめに、LaravelにはApplicationクラスというのがあります。
`bootstrap/app.php`でインスタンスを作ってるやつです。

```bootstrap/app.php

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

```

こいつです。こいつをみてみましょう。

```vendor/laravel/framework/src/Illuminate/Foundation/Application.php

class Application extends Container implements ApplicationContract, HttpKernelInterface
{
}

```

Containerクラスを継承してることからわかるように、このApplicationクラスはサービスコンテナ（=DIコンテナ)です。このContainerクラスの中にサービスをインスタンス化するメソッドがあります。

```vendor/laravel/framework/src/Illuminate/Container/Container.php

public function make($abstract, array $parameters = [])
{    
    return $this->resolve($abstract, $parameters);
}

```

こいつです。そのまんまの名前なのでわかりやすいです。
さて、順に追っていきましょう。resolveメソッドをみてみます。
以下、関連する場所だけ抜粋。

```vendor/laravel/framework/src/Illuminate/Container/Container.php

protected function resolve($abstract, $parameters = [])
{
    ~~~~

    if ($this->isBuildable($concrete, $abstract)) {
        $object = $this->build($concrete);
    } else {
        $object = $this->make($concrete);
    }

    ~~~~

    return $object;
}

```

makeを辿ってここまできたのでbuildの方を追ってみます（適当）。
例によって関係ありそうな箇所を抜粋してみます。

```vendor/laravel/framework/src/Illuminate/Container/Container.php

public function build($concrete)
{
    if ($concrete instanceof Closure) {
        return $concrete($this, $this->getLastParameterOverride());
    }
    $reflector = new ReflectionClass($concrete);
    $constructor = $reflector->getConstructor();

    $dependencies = $constructor->getParameters();
    
    $instances = $this->resolveDependencies(
        $dependencies
    );

    return $reflector->newInstanceArgs($instances);
}

```

buildメソッドの引数、`$concrete`にはクラス名かクラスのオブジェクト、もしくはClosureオブジェクトが入ります(たぶん)。
Closureだった場合は実行してreturnしてます。
そうでない場合、ReflectionClassのオブジェクトをつかって依存関係を解決していきます。
ReflectionClassについては[こちら](http://php.net/manual/ja/reflectionclass.construct.php)をご参考ください。

あとは順番に読んでいきましょう。

1. ReflectionClassオブジェクトを利用して、注入先クラス（クライアント）のコンストラクタを取得
2. コンストラクタのパラメータを取得
3. resolveDependenciesメソッドで注入する依存オブジェクトのインスタンスを作成（プリミティブなケースは説明を割愛。resolveDependenciesメソッドを読んでみてください。）
4. ReflectionClassオブジェクトを利用して先ほどインスタンス化した依存オブジェクトを引数に注入先クラス（クライアント）のインスタンスを作成しています。


# 終わりに

間違いあったら指摘おなしゃーす。
UnicodeEncodeError: '～' codec can't encode character '\x82' の原因と対処法


# 現象

以下のような`shift_jis`なバイト列を受け取ったとする。

```Python
# 元の文字列
s = 'aあ'
print(s)          # aあ
print(to_hex(s))  # 0061 3042

# shift_jis なバイト列に変換。OK
b = s.encode('shift_jis')
print(b) # b'a\x82\xa0'
```

これを`latin-1`と誤認してデコードしてしまった。当然中身はおかしなことになってしまう。

```Python
# shift_jis なバイト列を latin-1 と誤認して str型(UNICODE)に変換
s = b.decode('latin-1')

# １バイトずつUNICODE１文字、計３文字と誤変換！
print(to_hex(s)) # 0061 0082 00a0
```

いったんこうなってしまうと`shift_jis`に戻す（エンコード）こともできない。
ここで表題のエラーが発生する。
あるいは一見`utf-8`にはエラーなくエンコードできるのだが、中身がおかしい。

```Python
# UnicodeEncodeError: 'shift_jis' codec can't encode character '\x82' in position 1: illegal multibyte sequence
#b = s.encode('shift_jis')

# また、一見utf-8にはエラーなくエンコードできるが
b = s.encode('utf-8')
# 中身がおかしい
print(b) # b'a\xc2\x82\xc2\xa0'
```

よってファイルなどへの出力結果も正しくなくなる

```Python
with open('ret.txt', 'w', encoding='utf-8') as f:
    f.write(s) # U+0061 U+0082 U+00A0 の３文字出力される
```

# 対処法

- おかしくなった文字列を いったん誤ったエンコーディングで元のバイト列に戻す。
- あらためて正しいエンコーディングでデコードする。

とよい。

```Python
# おかしくなったstr型(UNICODE)を いったん元のバイト列に戻す
b = s.encode('latin-1')
print(b)

# あらためて正しいエンコーディングを指定してstr型(UNICODE)に変換。
s = b.decode('shift_jis')
print(s)
print(to_hex(s))
```
今回「誤認して`latin-1`でデコード」に気づかず、しかもデコード時にエラーが発生しなかったので解決に時間がかかってしまった。
デコード時にエラーが発生しなかったからといって`str(UNICODE)`型の文字列の中身が正しいとは限らないことに注意。

ちなみに上記で利用している`to_hex`関数は以下。

```Python
# strをhex表記に
# 'aあ' -> '0061 3042 '
def to_hex(s):
    ret = ''
    for c in s:
        ret += '{:04x} '.format( ord(c))
    return ret
```
postgresでcould not extend fileとなりdisk spaceがなくtruncateもできなくなっちゃったら

# 概要

postgresのdataファイルを配置しているsliceのdisk spaceがfullになってしまい
truncateしようにも `could not extend file` になってしまう場合の対応

こうなると `vacuum full` もできない状態になってるはず

通常はsliceに割り当てるdisk spaceを拡張するのだけれど
拡張しないで不要データを削除して対処する方法

# 対応方法

## おおまかな流れ

1. 別sliceなどでdiskがある場所にtable spaceを作る
2. alter table でいくつかのtableを1.で作成したtable spaceに移す
3. trucateできるようになるので、不要データをtruncateする
4. 2.でtable spaceを変更したtableをもとのtable spaceに戻す

※postgresはtruncateがcommitされたタイミングでdisk spaceを開放する

## 実施例


別sliceなどでdiskがある場所にtable spaceを作る

```
create tablespace backup location '/hoge/fuga';
```

いくつかのtableを作ったtable spaceに移す

```
alter table xxxxtable set tablespace backup;
```

この時点でdisk容量に少し空きができる。
truncateできるようになったら、不要なテーブルをtruncateする

```
truncate table 不要なtable;
```

disk容量が確保できたら table spaceをもとに戻す

```
alter table xxxxtable set tablespace 元のtablespace;
```

# 追記

postgresでwal（アーカイブログ）を有効にしている場合、アーカイブログが累積して
diskを使用している可能性がある。

postgresでは自動でアーカイブログをローテーションや削除する機能がないので
ほっとくとどんどん溜まってしまう。

アーカイブログの出力場所は `postgresql.conf` の `archive_command` で出力先を指定している。

この出力先にアーカイブログが溜まっている場合、不要なものを削除することでdisk spaceを確保できる。

## アーカイブログ削除対象

ベースバックアップ( `pg_basebackup` )取得時にできる `backup_label` の中を見ると削除できるアーカイブログがわかる。


```
START WAL LOCATION: 0/36000028 (file 0000000100000013000000EC)
```

のようになっている場合、　末尾ECより過去のログなら削除してもOK

ベースバックアップ取ってない場合は、アーカイブログ出力場所のファイルを見て、作成日が古いものを狙う。


## アーカイブログ削除方法

OSコマンドで消してもいいが、一応postgresのツールがあるので使う。

以下のように `pg_archivecleanup -n` をすると削除対象となるアーカイブログ一覧を取得できる。
指定したアーカイブログ名より過去のものすべてが削除対象となる。
`-n` をつけた場合は一覧出力だけで実際の削除はしない。

```
sudo -u postgres pg_archivecleanup -n [アーカイブログ出力ディレクトリ] [アーカイブログファイル名]
```

出力された結果がOKであれば `-n` を取って実行するとアーカイブログが削除される

```
sudo -u postgres pg_archivecleanup [アーカイブログ出力ディレクトリ] [アーカイブログファイル名]
```
Mysql で各グループの上位〇件までを取得する。（変数もlimitも使わないよ）

###クラス別の上位3位までのデータを取得したい。（同率の場合は名前昇順）

####・得点テーブル
| クラス  |  名前   |     得点 |
|:----------|----:|:---------:|
| 1組   |A        |       53 |
| 1組   |B      |       82 |
| 1組   |C      |       75 |
| 1組   |D        |       26 |
| 1組   |E        |       19 |
| 2組   |F        |      100 |
| 2組   |G        |       80 |
| 2組   |H        |       80 |
| 2組   |I        |       88 |
| 3組   |J        |       50 |
| 3組   |K        |       85 |
| 3組   |L        |       41 |

####上記をこうしたい
| クラス  |  名前   |     得点 |
|:----------|----:|:---------:|
| 1組   |B      |       82 |
| 1組   |C      |       75 |
| 1組   |A        |       53 |
| 2組   |F        |      100 |
| 2組   |I        |       88 |
| 2組   |G        |       80 |
| 3組   |K        |       85 |
| 3組   |J        |       50 |
| 3組   |L        |       41 |

####・取得SQL
```
SELECT 
a.クラス, a.名前, a.得点
, find_in_set(a.名前, b.rank) as 順位
FROM 得点テーブル a 
INNER JOIN (
   SELECT クラス, SUBSTRING_INDEX(GROUP_CONCAT(名前 ORDER BY 得点 DESC, 名前), ',', 3) as rank
   FROM 得点テーブル
   GROUP BY 1 
) b on a.クラス = b.クラス
WHERE FIND_IN_SET(a.名前, rank)
ORDER BY a.クラス, 順位
```
####・解説
GROUP_CONCATでグループ毎オーダー順に並べつつカンマ区切りの文字列として取得し、
SUBSTRING_INDEXでカンマ区切りの必要数でカットすることで上位の順位別キーのCSV文字列が取得できる。
FIND_IN_SETでキーとマッチするものだけ取得する。
FIND_IN_SETは文字列の何番目（先頭を1として）にマッチしたかを返してくれるのでそのまま順位になる。

####・別解 havingを使う
```
SELECT 
a.クラス, a.名前, a.得点
, find_in_set(a.名前, b.rank) as 順位
FROM 得点テーブル a 
INNER JOIN (
   SELECT クラス, GROUP_CONCAT(名前 ORDER BY 得点 DESC, 名前) as rank
   FROM 得点テーブル
   GROUP BY 1 
) b on a.クラス = b.クラス
HAVING 順位 <> 0 and 順位 < 4
ORDER BY a.クラス, 順位
```

####※注意
GROUP_CONCAT で連結できる文字数はDB設定に依存するので長くなりすぎる場合は設定の変更が必要。
Ignite UI for Angular のバージョニングについて

# はじめに

[Ignite UI for Angular](https://jp.infragistics.com/products/ignite-ui-angular) は修正や機能追加を継続して実施する継続的デリバリー (Continuous Delivery) を採用しており、非常に短いスパンでアップデートを実施しています。セマンティック バージョニングとは若干異なるバージョニングなので、混乱しやすいかもしれません。
下記の Wiki に Ignite UI for Angular のバージョニングについて解説されていますので日本語の説明を作りました。

[GitHub – Ignite UI for Angular versioning](https://github.com/IgniteUI/igniteui-angular/wiki/Ignite-UI-for-Angular-versioning)

注:このバージョニング規約は 4.x.x 以降が対象となります。(4系は[Ignite UI JSBlocks](https://www.npmjs.com/package/igniteui-js-blocks)という名前のパッケージです）

#バージョン規約

__\<Angular Major>__.\<Major>.\<Minor>

\<Angular Major> は Ignite UI for Angular がサポートする Angular のバージョンを示しています。現在、Angular のメジャーバージョンが 6 なので、Angular 6 系をサポートする Ignite UI for Angular のバージョンは 6 から始まります。

\<Angular Major>.__\<Major>__.\<Minor>

\<Major> は Ignite UI for Angular の__メジャー バージョン__を指し示します。このバージョンが上がる際には機能追加や重大な変更が含まれることがあるため、__過去のバージョンとの互換性が失われている__可能性があります。

例) Ignite UI for Angular 6.0.x と今後リリースされる 6.1.x には互換性がない可能性があります。([過去のリリースの例:5.2.0 リリースノート](https://github.com/IgniteUI/igniteui-angular/releases/tag/5.2.0))

\<Angular Major>.\<Major>.__\<Minor>__

\<Minor> は__マイナー アップデート__や__パッチ更新__を含み、同じメジャー バージョンとの互換性を保つように実装されています。

## ベータ版の場合

ベータ版には –beta が付与されているため、一目で判別できるようになっています。また、正式版のリリースまでより細かくリリースを行う場合があるため、\<Patch> が付与されます。(例: [5.2.0-beta.0](https://github.com/IgniteUI/igniteui-angular/releases/tag/5.2.0-beta.0))

\<Angular Major>.\<Major>.\<Minor>-beta.\<Patch>

# シナリオ

- 5.y.z → 6.y.z : サポートする Angular のバージョンが変更された。__重大な変更が含まれる可能性__がある
- x.1.z → x.2.z : Ignite UI for Angular の機能追加、向上が行われた。__重大な変更が含まれる可能性__がある
- x.y.1 → x.y.2 : Ignite UI for Angular のマイナー更新、あるいはパッチ修正が行われた。y というメジャーバージョン内では__互換性が保たれて__いる。
- x.y.z-beta.0 : x.y.z のベータ版。バージョン x.y.z が後日リリースされる。

# おわりに
通常の[セマンティック バージョニング](https://semver.org/lang/ja/)とは少し異なるため、わかりにくいよーと思っとります。