OmniAICreator/Qiita-1.07M huggingface dataset:
Railsでscaffoldを使わずに招待フォームを作成しよう1（index部分）


###説明している動画はこちらです。

https://www.youtube.com/watch?v=Zi-rZn-veAw&t=16s


###モデルを作成しよう

```bash:terminal
rails generate model User name:string email:string sex:integer age:integer address:integer attendance:integer opinion:text
```

データベースにテーブルがないことを確認しよう

```bash:terminal
mysql -uroot -p cebu_app_development -e "show tables"
```

テーブルを作成

```bash:terminal
rails db:migrate
```

テーブルが出来たこと、スキーマ情報を確認しよう

```bash:terminal
mysql -uroot -p cebu_app_development -e "show tables"
```

テーブル情報を確認しよう

```bash:terminal
mysql -uroot -p cebu_app_development -e "desc users"
```

###ルーティングを設定しよう

```ruby:config/routes.rb
get 'users', action: :index, controller: 'users'
```

###コントローラーを作成しよう


現在の場所は、/home/vagrant/cebu_appです。
cebu_appは、railsで作成したフォルダであれば、何でもいいです。
自分の環境と置き換えて、使って下さい。

このコマンドで確認できます。

```bash:terminal
pwd
```

```bash:terminal
vi app/controllers/users_controller.rb
```

```ruby:app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end
end
```

usersディレクトリの作成

```bash:terminal
mkdir app/views/users
```

```bash:terminal
vi app/views/users/index.html.erb
```

```erb:app/views/users/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Users</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Sex</th>
      <th>Age</th>
      <th>Address</th>
      <th>Attendance</th>
      <th>Opinion</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.email %></td>
        <td><%= user.sex %></td>
        <td><%= user.age %></td>
        <td><%= user.address %></td>
        <td><%= user.attendance %></td>
        <td><%= user.opinion %></td>
      </tr>
    <% end %>
  </tbody>
</table>
```

###表示するために、MySQLからデータを作成しよう

```mysql
INSERT INTO `users` (`name`, `email`, `sex`, `age`, `address`, `attendance`, `opinion`, `created_at`, `updated_at`) VALUES ('joji', 'joji@gmail.com', 0, 20, 1, 1, 'test', '2019-01-20 11:11:28', '2019-01-20 11:11:28')
```
macでPostgreSQLを使用する(Postgres.app & TeamSQL)

目的：MacOSX環境下でPostgreSQLおよびクライアントツールのTeamSQLをインストールする

## Postgres.appのインストール
Postgres.appはmacOSでpostgreSQLを簡単に扱うためのパッケージ
下記サイトから最新バージョンをインストールする
https://postgresapp.com/
![スクリーンショット 2019-01-20 20.15.35.png](https://qiita-image-store.s3.amazonaws.com/0/329378/83e96b39-4ea7-946f-19a3-e152f1b01916.png)
ゾウさんマークをApplicationsにドラッグしてインストール完了
## サーバーの設定を確認
appを起動すると、DB一覧が表示される
![スクリーンショット 2019-01-20 20.17.29.png](https://qiita-image-store.s3.amazonaws.com/0/329378/6881ca48-11ce-30e4-9871-c674410facaf.png)
Server Settingsボタンから、ポート番号を確認する
![スクリーンショット 2019-01-20 20.20.46.png](https://qiita-image-store.s3.amazonaws.com/0/329378/a18c1fa2-6381-b974-8889-58371368b98e.png)
なお、DBアイコンをダブルクリックするとターミナルが起動するため、詳細情報はそちらからでも確認できる
## TeamSQLのインストール
TeamSQLはPostgreSQLを含む様々なSQL言語をサポートするクライアントツール
UIが洗練されており、クエリの保存や履歴確認が容易なため、人気のGUIである
下記サイトからインストールする
https://teamsql.io/
![スクリーンショット 2019-01-20 20.27.53.png](https://qiita-image-store.s3.amazonaws.com/0/329378/579f8825-0fce-8ea8-3bd6-bcb973710716.png)
＊マークをApplicationsにドラッグしてインストール完了
ソフト起動後にユーザ登録をする
## TeamSQLからPostgreSQLのサーバに接続
TeamSQLを起動し、CONNECTIONS設定ウィンドウを開く
![スクリーンショット 2019-01-20 20.31.32.png](https://qiita-image-store.s3.amazonaws.com/0/329378/35f2d4b1-2d83-650e-4716-3d88d51de13c.png)
postgres.appで確認したサーバー情報をもとに設定をおこなう
初期設定であれば、Hostはlocalhost、ポート番号は5432となる
![スクリーンショット 2019-01-20 20.38.58.png](https://qiita-image-store.s3.amazonaws.com/0/329378/b0edf30e-0621-096b-0f82-8c4500c660e5.png)
無事に接続が完了すると、右のメニューバーにDBが表示されるようになる
![スクリーンショット 2019-01-20 20.44.23.png](https://qiita-image-store.s3.amazonaws.com/0/329378/e9418c83-70f0-3fd5-9fcc-77abe8589e9b.png)
RDSに株価情報連続アップロード

# 概要説明
RDS(MySQL)にアップロードする株式CSVを半分自動化。そのメモです。

## アップロード時
### モジュールとログイン情報を入力
```python
import csv
import codecs
import mysql.connector

rds = 'xxxxxxxxxxx'
con = mysql.connector.connect(
    host=rds,
    user="xxxx",
    password="xxxxx",
    database='xxxx'
)
cursor = con.cursor()
```

### UP用のメソッドを作成
```python
def to_RDS(csvdata):
        try:
        with codecs.open(csvdata, "r", "Shift-JIS") as f:
            reader = csv.reader(f)
            header = next(reader)  # 会社名情報
            next(reader)
            cursor.execute(f"DROP TABLE IF EXISTS `stock_table_{header[0]}`")
            cursor.execute(f"""CREATE TABLE IF NOT EXISTS `stock_table_{header[0]}`(
                            date DATETIME PRIMARY KEY ,opening_price FLOAT, high_price FLOAT, low_price FLOAT,
                             closing_price FLOAT,volume FLOAT,closing_price_adjustment_value FLOAT);""")

            sql = f"INSERT INTO `stock_table_{header[0]}` (date, opening_price, high_price, low_price, " \
                f"closing_price, volume, closing_price_adjustment_value) VALUES (%s, %s, %s, %s, %s, %s, %s);"
            for row in reader:
                cursor.execute(sql, (row[0], row[1], row[2], row[3], row[4], row[5], row[6]))
            con.commit()

    except mysql.connector.Error as e:
        print("Error code:", e.errno)  # error number
        print("SQLSTATE value:", e.sqlstate)  # SQLSTATE value
        print("Error message:", e.msg)  # error message
        print("Error:", e)  # errno, sqlstate, msg values
        s = str(e)
        print("Error:", s)
cursor.close()
con.close()
```

大本のCSVをファイルを見ると会社名情報が(0,0)に入ってますので、取得した`header`を`header[0]}`としてテーブル名に会社情報を入れています。[^1]` "Shift-JIS"`はエンコードです。
<img width="548" alt="スクリーンショット 2019-01-20 20.24.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/302092/263b7757-e045-afa5-427e-84ecd3d2289e.png">

[^1]: 本当はPythonのフォーマット形式ではなくSQL構文の形式を使って挿入したほうがいいそうです。
## ダウンロード時
### DOWN用のメソッド
```python
def get_RDS(cname):

    sql = f'select * from `stock_table_{cname}`'
    cursor.execute(sql)
    for row in cursor.fetchall():
        print('date', row[0], 'opening_price', row[1],
              'high_price', row[2], 'low_price', row[3],
              'closing_price', row[4], 'volume', row[5],
              'closing_price_adjustment_value', row[6])


get_RDS('6433 東証JQS ヒーハイスト精工(株)（機械）')


cursor.close()
con.close()

'''
結果
date 2018-01-04 00:00:00 opening_price 585.0 high_price 589.0 low_price 569.0 closing_price 580.0 volume 172100.0 closing_price_adjustment_value 580.0
date 2018-01-05 00:00:00 opening_price 586.0 high_price 619.0 low_price 586.0 closing_price 613.0 volume 337200.0 closing_price_adjustment_value 613.0
date 2018-01-09 00:00:00 opening_price 634.0 high_price 649.0 low_price 614.0 closing_price 626.0 volume 215300.0 closing_price_adjustment_value 626.0
...
```

連続アップできていたようでした。

> ちなみにこの株価CSVファイルは下記
[株式投資メモ](https://kabuoji3.com)

を使用させていただきました。
データのアップは半自動化できたのでこれをどうやってwebで出力しようか考え中...
[メモ]Vue.jsイベント修飾子一覧

## .stop
event.stopPropagation()を呼ぶ

```html
<div @click="handler('親')">
  <div @click.stop="handler('子')">
    ボタン
  </div>
</div>
```

通常同じイベントをハンドルしたDOMがネストされている場合、親要素に向かってイベントが連鎖する。
.stopをつけるとhandler('子')は実行されるが、handler('親')は実行されない。

## .prevent
event.preventDefault()を呼ぶ

```html
<a href="#top" @click.prevent="handler"></a>
```

handlerは実行されるが、#topに移動はしない。

## .capture
キャプチャモードでDOMイベントをハンドルする
つまりルート要素から順番にイベントが実行される

```html
<div @click="handler('親')">
  <div @click.capture="handler('子')">
    ボタン
  </div>
</div>
```

handler('親') -> handler('子')の順番で実行される

イベントが発生すると、キャプチャフェーズでルート要素から要素を探し、ターゲットフェーズでイベントハンドラ実行、バブリングフェーズでルートまで要素をさかのぼります。
通常はターゲットフェーズでイベントハンドラを実行しますが、キャプチャモードにするとキャプチャフェーズでイベントが発生します。

参照：[イベントフェーズ](https://qiita.com/hosomichi/items/49500fea5fdf43f59c58#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA%E3%81%A8%E3%81%AF)

## .self
event.targetが自分自身の場合のみハンドラが呼び出される
(子要素は呼び出されない)

```html
<div v-on:click.self="handler">ボタン</div>
```

## .native
コンポーネントのルート要素上のネイティブイベントをハンドルする

```html
<!-- コンポーネントをクリックするとhandlerが呼び出される -->
<my-component @click.native="handler"></my-component>

<!-- コンポーネントをクリックしてもhandlerが呼び出されない -->
<my-component @click="handler"></my-component>
```


## .once
最大１回ハンドラを呼び出す

## .passive
event.preventDefault()を呼び出さないことを明示
(.preventとの併用不可)

## .left
マウスの左クリックの場合のみハンドラを呼び出す

## .enter
キー修飾子。エンターボタンを押した場合にハンドラを呼び出す

参考：[基礎から学ぶVue.js](https://cr-vue.mio3io.com/)
phina.jsでinteractiveイベントを仕込む

phina.app.Object2Dもしくはphina.display.DisplaySceneクラスを継承したクラスオブジェクト（≒ほとんどの描画オブジェクト）には、マウスもしくはタッチで干渉（interaction）した際に何らかの処理を仕込むことができる。

interaction系イベントを有効にするには以下の手続きが必要。

1. interactiveプロパティを有効にする
2. コールバック関数を定義：```on('イベント名', function(){ /*コールバック*/})```、もしくは```on~```という関数を定義する

```js
phina.define('Box', {
  superClass: phina.display.RectangleShape,

  init: function() {
    this.superInit();
    this.setInteractive(true); // 1. interactiveを有効化
  },

  // 2-1. on[イベント名]関数を定義する場合
  onpointstart: function() {
    console.log('point start!');
  },
  
});

phina.define('MainScene', {
  superClass: phina.display.DisplayScene,

  init: function(options) {
    this.superInit(options);

    const box = Box()
      .setPosition(this.width*0.5, this.height*0.5)
      .addChildTo(this)
    // 2-2. onメソッドで定義する場合
    box.on('pointend', function() {
      console.log('point end!');
    });
  },

});
```


## イベントの種類と発火タイミング

イベント名 | 発火タイミング | 備考
--- | --- | ---
pointover | マウスポインタもしくは指がオブジェクトに乗っかった瞬間 | タッチ操作の場合、発火条件がpointstartに近くなるが、若干異なる（※）
pointstart | オブジェクト上でマウスボタンを押下、もしくは指でオブジェクトをタッチした瞬間 | 
pointstay | pointstart後、マウスボタンを押下しつづける、もくしは指を端末上においている間 | マウスボタン/指を押さえている間はオブジェクトの範囲外に出ても発火し続ける
pointmove | pointstayの状態でマウスポインタ、もくしは指を移動 | pointstay同様、オブジェクト範囲外に出ても発火し続ける
pointend |  pointstart後、マウスボタンもしくは指を離した瞬間 | 離す際、ポインタ・指はオブジェクト上に無くても良い
pointout | マウスポインタもしくは指がオブジェクトから離れた瞬間 | タッチ操作の場合、発火条件がpointendに近くなるが、若干異なる（※）

※例えばpointover/pointoutの場合、すでに端末上においた指をスライドしてオブジェクトに触れた/離れた際も発火する。

## 判定範囲
インタラクションの範囲は自由に設定することもできる。
判定範囲タイプは矩形（```rect```）と円形（```circle```）の二種類があり、
setInteractiveの第二引数、もしくはsetBoundingTypeで指定可能。

```js
box.setInteractive(true, 'rect');
this.setBoundingType('circle');
```

そして基本的には

  * rectの場合：width、heightプロパティ
  * circleの場合：radiusプロパティ

が範囲計算に使われる（実際はもうちょっと複雑）

### その他
- マウスカーソルの場合、interaction範囲内に入ると指（pointer）に変化することで判断できる

- interactionイベントの判定自体は**[ここ](https://qiita.com/pentamania/items/44c06223788612698fca)**でも書いている通り、各要素の更新処理（update等）の後に行われる。

- イベントハンドラでは引数で色々な情報を取得できる

```js
box.on('pointmove', function(event) {
  console.log(event.target); // 現在インタラクトしている対象（==box）  
  console.log(event.pointer.dx); // pointerオブジェクトから現在位置や移動量などを取得できる
  event.interactive.cursor.hover = "move"; // ホバー時のマウスカーソル形状を変更。（ただしinteractiveは全オブジェクト共有なので、適宜戻す必要がある）
})
```


**[>>オンラインエディタで動作確認](https://runstant.com/pentamania/projects/b3fd2c49)**

### 参考
- [phina.js のイベント一覧](https://qiita.com/hansel_no_kioku/items/32926abee3711963ce4b)
atcoder ABC105

Cは一見難しそうに見えるが、テストケースをもとに-2進数について考えれば解ける問題だった。Dについても、しっかりテストケースについて考えれば法則性が見えるので自力で解けた。
https://atcoder.jp/contests/abc105

#C問題
数字Nについて-2進数で表すという問題であるが、まず簡単な例として2進数を考えてみる。ある数M(10進数)を2進数に変えるには、Mを2割っていきあまりを記録していき、最後に記録したあまりを逆順に表示すれば良い。同様に-2進数についても同様にある数Nについて-2で割っていき、あまりを記録することで、最後にそれを逆順に表示すれば答えになる。ここで、一つ注意しなければならないのがNを-2で割る際に、Nが負の数だったら、N/-2商は+1しなければならない。

#D問題
M人の子供に、l~RまでのAについてのお菓子の和を均等に配るには、l~Rまでのお菓子の和がMの倍数でなければならない。まず、明らかに累積和をとる方が早いので、累積和をとる。その後、Mの倍数であることを確認するため、累積和のmodMをとる。ここで、0になったところは条件を満たすので答えにカウントする。ここで、累積和についてmodMをとった配列をSと呼ぶと、答えにカウントする条件はSについて、l,rを考えた時、S<sub>l-1</sub>,S<sub>r</sub>が等しいことを意味する。よってSについてそれぞれ出現する数を記録していき、出現回数がk回(k>=2)のものについて、k = 1になるまでforで回し、kを答えにカウントしていけば良い。
【Blender】[FBXエクスポートメモ]Blenderで作ったモデルデータをfbxにエクスポートしてUnityで取り込む。（静止画）

<font color="Magenta">【Blender】Blenderで作ったモデルデータをfbxにエクスポートして、Unityで取り込む。（静止画）</font>
<img width="447" alt="スクリーンショット 2019-01-20 20.14.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/5d1c6cfc-fa31-a5da-80d1-466b19aa92f0.png">

環境メモ
⭐️Mac OS Mojave バージョン10.14
⭐️Blender v2.79.6
⭐️Mac Book



1.「シーン」を選択し、「単位」の「長さ」を「メートル法」に変更する
単位（長さ）・・・・・なし -> メートル法
<img width="1152" alt="スクリーンショット 2019-01-20 19.42.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/70665ea9-3477-5354-3d81-2c108dbf82df.png">

2.「単位の倍率」を「1.0」にする
<img width="1129" alt="スクリーンショット 2019-01-20 11.45.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/8919e24f-5f93-a1d7-c0f5-d3ecfac30791.png">

3.FBX形式へエクスポートを選ぶ
「ファイル」ー「エクスポート」ー「FBX」を選ぶ
<img width="710" alt="スクリーンショット 2019-01-20 11.48.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/805c1657-ec43-a829-3a99-36a144507e2d.png">

4.「FBXをエクスポート」の内容で「メイン」を選択する。
<img width="491" alt="スクリーンショット 2019-01-20 19.51.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/9cbfe6c4-7ca2-82d1-9047-d6f1e8e7c059.png">

5.「ジオメトリ」を選択する
・モディファイアーを適用
・モディファイアーのレンダー設定を使用
をチェックONする
<img width="644" alt="スクリーンショット 2019-01-20 11.50.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/55bd62e0-d2fe-ba22-0537-6763b7ef9585.png">

6.「アーマチュア」は、そのまま変更なし
<img width="482" alt="スクリーンショット 2019-01-20 11.50.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/2730ca42-d909-41d1-8cbf-80b7f8f425ae.png">

FBXでエクスポートし、Unityで取り込む
<img width="684" alt="スクリーンショット 2019-01-20 12.05.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/18203329-1568-2a03-8a1d-2f6a4790e7de.png">

（Rotation　Y軸を「-90」にしました）
<img width="431" alt="スクリーンショット 2019-01-20 20.10.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/bb0ef2c2-b0f3-1a58-ccc9-65ba666b1082.png">


※類似の記事はこちら↓↓にも記載してます。
【Blender】UV展開とベイクをしてからUnityへ取り込む
https://qiita.com/nonkapibara/items/adcf7c923df97e4679bd
Herokuで遅延処理（DelayedJob）を実装/設定する

今回想定しているのは、ユーザーが立てた予定（Plan）に対して、その予定日時の24時間前と1時間後に、ユーザーへの通知処理を行う（メールやLINEなど）というのもの。

遅延処理の仕組みにはRails標準のDelayedJobを使う。

Herokuの公式ドキュメントをみながら書きました。
https://devcenter.heroku.com/articles/delayed-job

# 環境設定編
### 1. gemを入れる
```ruby
gem 'delayed_job_active_record' #Gemfileに追加
---
bundle install
```

### 2. delayed_jobを作成
```bash
rails generate delayed_job:active_record
rails db:migrate
```
jobはレコードとして保存されるので、マイグレーションを忘れずに。

### Heroku用のProcfileを作成
Herokuではworkerを起動するためにProcfileが必要なので、作成します。

```bash
touch Procfile
---
worker: bundle exec rake jobs:work
```


#実装編
### 1. 通知処理を作る
```ruby
class Plan < ApplicationRecord
  ...
  def pre_notify
   # 事前に行う通知
　　...
  end

  def after_notify
   # 事後に行う通知
　　...
  end
end
```

### 2. 遅延させて実行する
メソッドを呼ぶ時に、クラス（インスタンス）とメソッド名の間にdelayを挟むと、workerへ処理が渡されます。

```ruby
# scheduledカラムに予定日時がはいいている
# queueでキューのパラメータを渡せる

@plan = Plan.find_by(id: params[:id])
@plan.delay(run_at: @plan.scheduled - 24.hours, queue: 'plan_' + @plan.id.to_s).pre_notify
@plan.delay(run_at: @plan.scheduled + 1.hours, queue: 'plan_' + @plan.id.to_s).after_notify
```

# まとめ
思ってたよりも作業が少なかったけど、無事に遅延処理できました。
久しぶりにrubyに触りたくなったのでアップデートする

久しぶりにrubyをやりたくなったのでアップデートしてみた。
rubyの情報は豊富なのだが、いろいろ見ないとできなかったのでメモ。

bundlerとcomposerは似ている感じ。


```bash
// rbenvでインストールできるrubyのバージョンを確認
rbenv install --list

// install
rbenv install 2.6.1

// 使えるversionを確認
rbenv versions

// 使いたいバージョンを指定
rbenv global 2.6.1

// 確認
ruby- v

// gem自体をアップデート
gem update --system

// bundler入れる
gem install bundler

// railsを入れる
gem install rails

```

参考
rbenvでRubyのバージョンを最新安定版にupdate
https://qiita.com/_kanacan_/items/c1499f6c13b1c41da982#%E3%81%BE%E3%81%A8%E3%82%81
SVProgressHUDのモック化

# はじめに

UIのユニットテストを書く時の阻害要因になるのがSVProgressHUDの使用箇所（使っている場合）。こいつをなんとかモック化してみました。

# 問題

OCMockを使ってSVProgressHUDをモック化する場合、普通、以下の感じになります。

```objc

@implementation MockSVProgressHUD

+ (void)startMocking {
   
    mock = OCMClassMock([SVProgressHUD class]);
       
    [[[mock stub] andCall:@selector(showSuccessWithStatus:) onObject:self] showSuccessWithStatus:[OCMArg any]];
    [[[mock stub] andCall:@selector(showErrorWithStatus:) onObject:self] showErrorWithStatus:[OCMArg any]];
    [[[mock stub] andCall:@selector(dismiss) onObject:self] dismiss];
    
}

+ (void)showSuccessWithStatus:(nullable NSString*)status {
}

+ (void)showErrorWithStatus:(nullable NSString*)status {
}

+ (void)dismiss {
}
	
```

ところが、dismissメソッドはクラスメソッドとインスタンスメソッドの両方があり、その場合、SVProgressHUDのdismissメソッドが呼ばれます。さてさて

# 解決策

というわけで、SVProgressHUDのソースを読むと以下のようにシングルトンになっています。

```objc

+ (SVProgressHUD*)sharedView {
    static dispatch_once_t once;
    
    static SVProgressHUD *sharedView;
#if !defined(SV_APP_EXTENSIONS)
    dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[[[UIApplication sharedApplication] delegate] window].bounds]; });
#else
    dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; });
#endif
    return sharedView;
}

```

以下のようにクラスメソッドからはそのシングルトンを直接、あるいは間接的に呼び出しています。

```objc

+ (void)setViewForExtension:(UIView*)view {
    [self sharedView].viewForExtension = view;
}

```

ということはそのsharedViewメソッドのreturn値をnilにすれば、とりあえずモックとして機能します。実装例を示します。

```objc

// プライベートメソッドを強引に開示する。
@interface SVProgressHUD(Testing)
+ (SVProgressHUD *)sharedView;
@end

@implementation MockSVProgressHUD

+ (void)startMocking {
    mock = OCMClassMock([SVProgressHUD class]);
    [[[mock stub] andCall:@selector(sharedView) onObject:self] sharedView];
}

...

// nilを返す事によってMock化する。
+ (SVProgressHUD *)sharedView {
    return nil;
}

```

無事、モック化できました。もっと挙動を制御したい時、テストスパイに仕立てたい時は、nilを返すのではなく、偽装するオブジェクトを返して各種インスタンスメソッドを実装する必要があるでしょう。

# 課題

- OCMockを勉強すればもっとうまい方法があるかも。
- SVProgressHUDの内部実装に依存する方法なので、将来バージョンアップして内部実装が変わった時にこの策は破綻するかも？。
OracleMasterBronze 5章　インスタンスのアーキテクチャ

<h1>OracleMaster 5章　インスタンスのアーキテクチャ</h1>
この記事は初学者向けです。
わかりづらいことをなるべくわかりやすく書いています。
認識間違いがあればご指摘お願いします！

<h1>概要</h1>
OracleMaterBronzeを勉強していて、インスタンスのアーキテクチャがざっくりわかりはじめてきたので備忘録も兼ねてまとめていきます。

まずは下記３点から紹介していこうと考えています。
1.SGA(システムグローバル領域)
2.バックグラウンドプロセス
3.PGA(プログラムグローバル領域)



<h1>1.SGA(システムグローバル領域)</h1>

###1-1. 何のための機能なのか
  OSの共有メモリ内にSGAを確保し、データをキャッシュすることでパフォーマンスの悪化を防ぐ。

ちょっと詳しく↓
  OSの共有メモリとは、多数のユーザーが同時にアクセスできる領域のこと。つまり共有メモリ上に作成し 
  たSGAも多数のユーザーが同時にアクセスできるということであり、この領域にキャッシュすることで本 
  来ディスク→メモリ→CPUと処理していくところをメモリ→CPUと短縮できるので、処理が早くなる。

###1-2.どんな内容をキャッシュするのか
  ①データベースバッファキャッシュ
  ②共有プール
  ③REDOログバッファ
  ④ラージプール
  ⑤Javaプール
  ⑥Streamsプール

##①データベースバッファキャッシュ
一度問い合わせがあったデータをメモリ領域に保存しておき、次回呼び出し時に保存しておいたデータを渡すことで
データ読み込み速度を向上させる。

また、更新されたデータをすぐにディスクに書き込まず、一旦データベースバッファキャッシュに保存し、チェックポイントが発行されタイミングでDBライターというプロセスによりディスクに書き込まれます。
この処理を行うことでディスクへの書き込み回数を減らるし、書き込み回数を減らすことで更新速度を向上させています。
(チェックポイントやDBライターはバックグラウンドプロセスで出てきます！焦らずにじっくり学んでいきましょう。)

ハードディスクの仕組みを理解しているとわかりやすいかもしれません！


##②共有プール
最近実行したSQLやデータディクショナリ情報を格納する
よくわかんないですね！

下記三つから構成されるらしい。
ライブラリキャッシュ
直前に実行したSQL、SQLの解析結果をキャッシュ
（初めての奴は理解するのに時間がかかるけど、一回やったやつは「これ進〇ゼミでやったやつだ！」って感じでスラスタ解けますよ）

データディクショナリキャッシュ
テーブルやインデックスなどのデータベースオブジェクトの定義や権限などを格納
（すみません、〇〇やっていいですかっていう感じのを毎回許可とるのめんどいから一回許可とったらOKって感じです！）

ユーザグローバル領域
セッションやカーソル情報を保存。ラージプールがある場合はそっちに保存されます。
（セッションは接続しているユーザー、カーソル情報はいまどこのSQLまで処理しました！っていう情報です。）

本日はここまでにして、後日続きを書いていきます！
XserverにSSHでログインしてscpで管理する


FTPやFTPSでファイルをアップロード/ダウンロードするのはセキュリティ面からよろしくないということで、SSHでserverにログインしてgitでデータの取得をしたいのでその手順です。

## 環境

- サーバはレンタルサーバーの「Xserver」
- Macのteminal

## 手順

Xserverの公式サイト「[SSH設定](https://www.xserver.ne.jp/manual/man_server_ssh.php)」で記載されているようにSSHでserverにログインするには「公開鍵」を自分で生成するか、サーバー上で「公開鍵認証用鍵ペア」を生成するかのどちらかになります。

> お客様にて生成の公開鍵を登録していただく方法と、サーバー上で公開鍵認証用鍵ペアを生成し秘密鍵をダウンロードしていただく方法がありますので、下記をご参照の上、生成または登録を行ってください。

### SSH設定をONにする

- Xserverのサーバーパネルにログイン
- ```SSH設定```でSSH設定を```ON```にする 

### 公開鍵認証用鍵ペアの生成

1. XserverのSSH設定で```公開鍵認証用鍵ペアの生成```タブを選ぶ
2. ```パスフレーズ```を入力する
3. ```{サーバーID}.key```をダウンロード
4. homeディレクトリの```.ssh```にダウンロードしたkeyファイルを格納
5. keyファイルのパーミッションを```600```に設定
6. サーバーにログイン

``` terminal:パーミッションを600に設定
$ chmod 600 {サーバーID}.key
```

``` terminal:サーバーにログイン
$ ssh -i ~/.ssh/{サーバーID}.key -p 10022 {サーバーID}@{サーバー番号}.xserver.jp
```

### 公開鍵を登録

1. terminalで秘密鍵と公開鍵を生成
2. パスフレーズを設定
3. homeディレクトリの```.ssh```に```hoge_rsa```と```hoge_rsa.pub```を格納
4. ```hoge_rsa```と```hoge_rsa.pub```のパーミッションを600にする 
5. XserverのSSH設定で```公開鍵登録・設定```タブを選ぶ
6. ```hoge_rsa.pub```の中身を貼付
サーバーにログイン

``` terminal:秘密鍵と公開鍵を生成
$ ssh-keygen -t rsa -f hoge_rsa
```

``` terminal:パーミッションを600に設定
$ chmod 600 hoge_rsa
```

``` terminal:サーバーにログイン
$ ssh -i ~/.ssh/hoge_rsa -p 10022 {サーバーID}@{サーバー番号}.xserver.jp
```

### gitが使えれば

「Xserver」はレンタルサーバー(共有サーバー)なので```git```が入ってないのですが、gitが使えればSSHでログインして```git clone```でremoteのデータを取得、```git pull```で本番サイトを更新などをすることができます。

## scpでサーバー/ローカルのデータをコピー

### サーバーのファイルをローカルにコピー

``` terminal:秘密鍵でserverにログイン
$ scp -i ~/.ssh/{秘密鍵名}_rsa -P 10022 {サーバーID}@{サーバー番号}.xserver.jp:{サーバーのpath}/test.txt {ローカルのpath}
```

### ローカルのファイルをサーバーにコピー

``` terminal:秘密鍵でserverにログイン
$ scp -i ~/.ssh/{秘密鍵名}_rsa -P 10022 {ローカルのpath}/test.txt {サーバーID}@{サーバー番号}.xserver.jp:{サーバーのpath}
```

### サーバーのディレクトリをローカルにコピー

``` terminal:-rはディレクトリをコピーするオプション
$ scp -r -i ~/.ssh/{秘密鍵名}_rsa -P 10022 {サーバーID}@{サーバー番号}.xserver.jp:{サーバーのpath}/test {ローカルのpath}
```

### ローカルのディレクトリをサーバーにコピー

``` terminal:-rはディレクトリをコピーするオプション
$ scp -r -i ~/.ssh/{秘密鍵名}_rsa -P 10022 {ローカルのpath}/test {サーバーID}@{サーバー番号}.xserver.jp:{サーバーのpath}
```

## 参考サイト

- [SSH設定 | レンタルサーバー【エックスサーバー】](https://www.xserver.ne.jp/manual/man_server_ssh.php)
- [プロなら絶対使わない、本当は怖い「FTP」 知らずに使っていませんか？](https://tajuso.com/ftp_no_encryption)
- [【 scp 】コマンド――リモートマシンとの間でファイルをコピーする](http://www.atmarkit.co.jp/ait/articles/1701/27/news009.html)
ansible+vagrantでwildflyの環境を構築する

AnsibleはゲストOSにエージェントを構築しなくともSSHさえ繋がるなら設定とかをごにょごにょ自動化してくれる優れもの。
ということで、vagrantで構築したゲストOSに対して設定をしたい場合の書き方を備忘録として残す。
今回はWildflyをAnsible Galaxyを利用して構築してみる。



# コマンド
``` bash
brew install python
pip3 install pipenv

mkdir ansible-wildfly
cd ansible-wildfly

pipenv install ansible
pipenv shell

vagrant box add centos/7
vagrant init centos/7
mkdir data #今回関係ないが共有フォルダに使用する
```
Ansibleはpipから入れることにする。
ホスト環境に直接入れちゃうより入れたり消したりが楽なため。
そのあと以下のファイルを準備する。


#準備するもの
## Inventory
``` :hosts
192.168.33.10 ansible_connection=ssh ansible_ssh_port=22 ansible_ssh_user=vagrant ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key
```

ansible_connectionはデフォルトでSSHなので不要、ポートも通常は２２なのでいらないかも。

## Playbook
``` yml:main.yml
- hosts: wildfly
　　sudo: yes
　　roles:{ role: inkatze:wildfly }
```
今回はWildflyで出てきたinkatze:wildflyを利用してみる

## Vagrantfile
``` rb:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"

  config.vm.network "forwarded_port", guest: 8080, host: 8080
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.synced_folder "./data", "/vagrant_data"

  config.vm.provider "virtualbox" do |vb|
    vb.memory = "4096"
    vb.cpus = 2
  end
end
```
ポート8080はWildflyが使うデフォルトポート。メモリーは通常の１ギガだとおそらく実行可能要件を満たさないので４ギガほどにあげる。

## 実行
``` bash
vagrant up
ansible-playbook -i hosts main.yml
```

なお、一度環境を潰して二回目を行おうとするとエラーとなる。エラーの原因は一度建ててしまったSSHのフィンガープリントが~/.ssh/known_hostsに保存されているからである。
対象のホストをknown_hostsから削除すればうまくいく。
tableView.insertRowsでハマった

どれだけセル更新しようと思って配列更新しても反映されなかったけどすごい初歩的なミスだった気がする。
雑だけど書いておく。

tableView.insertRows(at: [IndexPath(row: i, section: j )], with: UITableViewRowAnimation.*)で挿入（変更通知）する位置iと、
tableView:cellForRowAtでテーブルセルに表示する配列の要素位置iは揃える必要があって、そこに気づけなかった。
まあ当たり前だとは思うんだけど…

自分はinsertRowsで挿入する前に対象配列をappendで更新（＝配列末尾に追加）してるにも関わらず、
insertRowsのIndexPathのrowに0を指定してたから、
いくら配列更新しても、配列の0番目要素がinsertRowされて、
無限に配列の0番目要素がセルに追加される形に…

なおappendで更新するならIndexPath(row: 配列.count-1, section: <任意>)とすればよい
AWSでLaravelを立ち上げた

#手順
まずLAMP環境を構築。
[チュートリアル: Amazon Linux 2 に LAMP ウェブサーバーをインストールする](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html)

Laravelのインストールなど。
[AWSのEC2を立ち上げてLaravelのログイン機能を動かすまで](https://qiita.com/atto/items/e1effd28c212c3829cb0)

.envの設定。
[.envの設定値の参考:保存版！Laravelの.envでできること大全](https://blog.capilano-fw.com/?p=1382)

#つまづいた

バージョンを確認しようと思ったらエラーが出ました。
autoload.phpがないとのこと。

~~~
[ec2-user@　 ・・ test-laravel]$ php artisan -V
PHP Warning:  require(/var/www/laravel/vendor/autoload.php): failed to open stream: No such file or directory in /var/www/laravel/artisan on line 18
PHP Fatal error:  require(): Failed opening required '/var/www/laravel/vendor/autoload.php' (include_path='.:/usr/share/pear:/usr/share/php') in /var/www/laravel/artisan on line 18
~~~


よく見たらプロジェクト作成時にエラーが出てました。

~~~
$ ~/composer.phar create-project --prefer-dist laravel/laravel test-laravel
~~~

~~~
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - phpunit/phpunit 7.5.x-dev requires ext-dom * -> the requested PHP extension dom is missing from your system.
    -
~~~

ext-domが必要だけどなかったとのこと。下記コマンドでインストール、

~~~
$ sudo yum install php-xml
・
・
完了しました!
~~~

無事に確認できました。

~~~
[ec2-user@　 ・・ test-laravel]$ php artisan -V
Laravel Framework 5.7.21
~~~

#結果

立ち上がりました。
http://**Your Elastic IP**/index.php/login

![Test-Laravel 2019-01-20 19-38-46.png](https://qiita-image-store.s3.amazonaws.com/0/336536/63e4f85d-36f1-2dbd-e72f-1d3ee56cf876.png)

#追記
このままだとphpMyAdminを表示できないので下記を行う。
[バーチャルホスト の設定（Amazon Linuxにて）](https://qiita.com/outase/items/9bf2766c34fd752ce069)


#後々
[参考：[Laravel 5.5] 読み込む.envファイルを環境ごとに切り替える](https://qiita.com/takaday/items/b992c7d8cd69343b6626)
[参考：Laravelの .env の値はconfig()経由で使う。](https://hiroto-k.hatenablog.com/entry/2018/03/28/213000)
↑開発の際は気をつけねば
Unity PlayMakerでマウスクリック系システムイベントを受け取る（System EventsとUI Eventsの違いって？

#いきなり結論

* System EventsのMOUSE UPなどのマウス系イベントを受け取るには、何らかのコライダが必要
* UI EventsのUI CLICKを受け取るにはButtonコンポーネントが必要（これ公式に書いてあった）

> Sent when a Button is pressed. Game object needs a Button component.
（公式ヘルプ[Events](https://hutonggames.fogbugz.com/default.asp?W128)より引用）

（ユーザーイベントを用意してInput系アクションでSend Eventする方法はここでは省略します）

#はじめに（きっかけ）

2Dゲームで（[こんなの](https://unityroom.com/games/pmrpg1)）「ボタン押下」と「画面内マウスクリックでメッセージ送り」の両方をやるときに、System Eventsの「MOUSE UP」とUI Eventsの「UI CLICK」のどちらを使えばよいのかわからなかったので、調査・実験してみた。

#前提情報

* Unity 2018.3.0f2
* PlayMaker 1.9.0.p5

#試したこと

### ①2DでButton

2DプロジェクトでButtonオブジェクトに「MOUSE UP」「UI CLICK」イベントが届いたらDebug Log出力するFSMをやってみた。

![スクショ.jpg](https://qiita-image-store.s3.amazonaws.com/0/166815/d4008085-7871-59de-d17c-c0b31d4998e0.jpeg)

**→ ボタンクリック時に「UI CLICK」イベントのみ届いた。**

> え？「MOUSE UP」は届かないの？

### ②2DでSprite

2DプロジェクトでSpriteオブジェクトに「MOUSE UP」「UI CLICK」イベントが届いたらDebug Log出力するFSMを(ry

**→ クリックしてもどちらのイベントも届かなかった。**

>「UI CLICK」が届かないのはわかるけど「MOUSE UP」も届かない？
>じゃあ「MOUSE UP」はどうやったら届くの？？

### ③3DでCube

3DプロジェクトでCubeオブジェクトに「MOUSE UP」「UI CLICK」イベントが届いたらDebug Log出力(ry

**→ クリック時に「MOUSE UP」イベントのみ届いた。**

> 「MOUSE UP」届いた！じゃあ「MOUSE UP」が届く条件って？

### ④3DでCube（Box Collider無効）

3DプロジェクトでCubeオブジェクトの「Box Collider」コンポーネントのチェックボックスを外して無効にした状態で、「MOUSE UP」「UI CLICK」イベントが届いたらDebug Log出力(ry

**→ クリックしてもどちらのイベントも届かなかった！**

>つまり、「MOUSE UP」に必要なのはコライダ！

### ⑤2DでSprite（Box Collider 2D追加）

2DプロジェクトでSpriteオブジェクトに「Box Collider 2D」コンポーネントを追加した状態で、「MOUSE UP」「UI CLICK」イベントが届いたらDebug Log出力するFSMを(ry

**→ クリック時に「MOUSE UP」イベントが届いた！やったー！**

#おわりに

すみません、これがQiitaデビューです。
もし、記事の内容に間違いや修正すべき点などありましたら、優しく教えていただければ修正していきたいと思います。
取り急ぎざっと書いてみたので、あとで手を入れるかもしれません。
自分用備忘録として書いた部分もありますが、参考になれば幸いです。
~~ポエムでしたらすみません。~~
ZabbixServer4.0をRHEL7.6にinstall

## 環境
* Red Hat Enterprise Linux Server release 7.6 (Maipo)
* zabbix-server-mysql-4.0.3-1.el7.x86_64

## 参考
[nstall_from_packages rhel_centos](https://www.zabbix.com/documentation/4.0/manual/installation/install_from_packages/rhel_centos)

## install
### zabbix server + frontend
```bash
# zabbix repositoryの追加
rpm -ivh https://repo.zabbix.com/zabbix/4.0/rhel/7/x86_64/zabbix-release-4.0-1.el7.noarch.rpm

# php周りの依存関係解消の為optionalリポジトリを有効化(zabbix-web-mysqlで使用)
yum-config-manager --enable rhui-REGION-rhel-server-optional

# zabbix server(mysql) install
yum install zabbix-server-mysql

# zabbix frontend install(ここでhttpdも入る)
yum install zabbix-web-mysql zabbix-web-japanese

```

### mariadbのinstallと初期設定

```bash
# mariadbのistall
yum install mariadb-server

# mariadbの起動
systemctl start mariadb && systemctl status mariadb
systemctl enable mariadb

# mysql_secure_installationの実行
mysql_secure_installation

# 
Set root password? [Y/n] n
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y

# zabbix用databaseとユーザの作成
zabbix_pass=xxxxxxxx
# zabbix server
mysql -uroot -e "create database zabbix character set utf8 collate utf8_bin;"
mysql -uroot -e "grant all privileges on zabbix.* to zabbix@localhost identified by '$zabbix_pass';"
```

### zabbix databaseのsetup

```bash
# create.sqlの実行(zabbix server)
zcat /usr/share/doc/zabbix-server-mysql*/create.sql.gz | mysql -uzabbix -p zabbix
```


### 

```bash
# DBHost=localhost、DBName=zabbix、DBUser=zabbixはそのまま利用。パスワードのみ設定する
# zabbix server
sed -i "s/# DBPassword=/# DBPassword=\nDBPassword=$zabbix_pass/g" /etc/zabbix/zabbix_server.conf
```

### zabbix serverの起動

```bash
# 起動
systemctl start zabbix-server && systemctl status zabbix-server
# 自動起動も有効化しておく
systemctl enable zabbix-server
```

### httpd側の設定

```bash
# zabbix.conf内のphpの変数”date.timezone"修正
# php_value date.timezone Europe/Rigaをphp_value date.timezone Asia/Tokyoに変更
# httpd の起動
systemctl start httpd && systemctl status httpd
# 自動起動設定
systemctl enable httpd
```

### zabbix Webuiからの設定
・　http://{zabbix-serverのip}/zabbixにアクセス

![スクリーンショット 2019-01-06 2.09.43.png](https://qiita-image-store.s3.amazonaws.com/0/90505/bde08310-2f27-bb2a-3f8e-e90f593e69e2.png)

・環境の事前チェック

![スクリーンショット 2019-01-06 2.10.04.png](https://qiita-image-store.s3.amazonaws.com/0/90505/17452c8c-759d-61c7-c157-4f3e6f5b1baf.png)

・DB接続情報
![スクリーンショット 2019-01-06 2.10.27.png](https://qiita-image-store.s3.amazonaws.com/0/90505/ae4b3adb-543e-0280-cdc6-cbf21b194c4e.png)

・Zabbix-Server情報
![スクリーンショット 2019-01-06 2.11.01.png](https://qiita-image-store.s3.amazonaws.com/0/90505/2406b8f2-a29b-0cde-cae9-edf5d8fef5e9.png)

・Installのサマリ
![スクリーンショット 2019-01-06 2.11.11.png](https://qiita-image-store.s3.amazonaws.com/0/90505/dd13b557-e975-dd64-4958-2ebc470422ad.png)

・　Install完了
![スクリーンショット 2019-01-06 2.11.22.png](https://qiita-image-store.s3.amazonaws.com/0/90505/50c9f83c-b9d4-2b4b-abf9-90028ade5b1a.png)

初期パスワードはzabbix
![スクリーンショット 2019-01-06 2.11.38.png](https://qiita-image-store.s3.amazonaws.com/0/90505/e92045cf-1554-9bb3-c05d-cdebc248e403.png)
細菌ゲノムの遺伝子を高速に比較するLS-BSR pipelineを使う

# LS-BSR piplineとは
Jason W らが作成した細菌のゲノム間の遺伝子を比較しBLASTスコア比を返してくれるツール．
Large scale Blast Score Ratioを略してLS-BSR．

# 今回の解析に必要なデータセット
LS-BSR のディレクトリに格納されている`test_data/genomes`を用いる．

データセットとして，
**E2348_69_all.fasta**
**H10407_all.fasta**
**O157_H7_sakai_all.fasta**
**SSON_046_all.fasta**
の４株が用いられている．

# 2. インストール
## 依存関係について
LS-BSR は様々なツールに依存していて正直しんどい．

**依存ツール**
Python >2.7 and <=3.5
BioPython
Prodigal - Required for de novo gene prediction only
VSEARCH - Optional
USEARCH - Optional
CD-HIT - Optional
Blast+ - Optional
Blat - Optional
Diamond - Optional

一気に入れたい場合はconda とかで．

```bash
conda create -n ls_bsr python=3.5
conda activate ls_bsr
conda install blast vsearch cd-hit prodigal ucsc-blat diamond biopython
git clone https://github.com/jasonsahl/LS-BSR.git
python setup.py install

# テストしよう
python tests/test_all_functions.py
```
# 3. 実行コマンド
LS-BSR の実行には４つ方法がある．
tblastn, blastn, usearch, diamond を用いた方法である．

```bash
# De novo 遺伝子予測方法
# -p が用いるプロセッサ数， -d がfasta(塩基)が入ったファイル， -c でusearch を指定している
ls_bsr.py -p ${n_cores} -d test_data/genomes -c usearch

# tblastn によるスクリーニング方法
ls_bsr.py -d test_data/genomes -g test_data/genes/ecoli_markers.fasta

# blastn による遺伝子スクリーニング方法
 ls_bsr.py -d test_data/genomes -g test_data/genes/ecoli_markers.fasta -b blastn

# Diamond によるアノテーションに対しての遺伝子検索方法
ls_bsr.py -d test_data/genomes -g test_data/genes/genes.pep -b diamond
```

# 4. 出力ファイルについて
今回は，*De novo* 遺伝子予測方法で実行した．

```bash
2019120134338_bsr_matrix.txt
2019120134338_consensus.pep
2019120134338_duplicate_ids.txt
2019120134338_run_parameters.txt
2019120134338_consensus.fasta
2019120134338_dup_matrix.txt
2019120134338_names.txt
```
というように，日付が先頭についたファイルが出力される．
`-x`をつければ，出力ファイルの_より前の部分の名前を変更できる．

# 5. 可視化について
出力ファイルの可視化について，様々な方法を使うことができる．
R,MeVでヒートマップを書くとか，iTOLで系統樹と一緒に表示させるとか．

以下にRでヒートマップを書いたが，そもそもこのデータは行数が多すぎてヒートマップに適していないので，80行だけランダムサンプリングして描画している．
入力側（ｘy軸）を数個の遺伝子とかにして，データベース側（x軸）に当てるとかいう状況だとヒートマップがいいと思う．

```R
#heatmap の描画ライブラリを読み込む
library(pheatmap)

#データを読み込む&前処理
lsbsr<-read.table("2019120134338_bsr_matrix.txt")
lsbsr<-as.matrix(lsbsr)

# ランダムサンプリングで８０行持ってくる
lsbsr80<-lsbsr[sample(nrow(lsbsr), 80), ]

#PDF に出力する
pdf("heatmap.pdf",width=10,height=15,pointsize = 8)

# heatmap 作成
pheatmap(lsbsr80)

# 描画終了
dev.off()
```

できたのがこんなかんじ
<img width="727" alt="スクリーンショット 2019-01-20 19.25.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/222325/9523eb81-b465-4855-06e9-121a0a316704.png">

# 参考HP
[LS-BSR(Large Scale Blast Score Ratio)](https://github.com/jasonsahl/LS-BSR)

[LS-BSR Tutorial Project](https://github.com/haruosuz/mgsa/tree/master/lsbsr)

# LS-BSRの論文
[The large-scale blast score ratio (LS-BSR) pipeline: a method to rapidly compare genetic content between bacterial genomes](https://peerj.com/articles/332/)
zerologを標準logの代用にするための設定

ログレベルのない標準logでは辛くなってきたので、高速構造化Loggerである[zerolog](https://github.com/rs/zerolog)のPretty loggingで代用するための設定について調べました。構造化ログを知らなかった無知が書いております。

### 公式で紹介されている例
zerolog公式でもPretty loggingの設定方法が軽く紹介されているのですが、その出力は

    2006-01-02T15:04:05+09:00 | INFO  | ***Hello World**** foo:BAR

で、個人的にマイクロ秒とファイル名、行番号が欲しかったのですが(あとタイムゾーンは不要)検索では見つけられず、godocを眺めつつの試行錯誤で探しました。

### 設定方法
以下の手順でできました。なお移行中に標準logと混在しても困らないようにzerolog/logはzlogにエリアスしています。またglobal loggerを書き換えています。

```go
import (
	"fmt"
	"log"
	"path/filepath"
	"strings"
	"time"

	"github.com/rs/zerolog"
	zlog "github.com/rs/zerolog/log"
)

func initLog() {
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
	zerolog.TimeFieldFormat = time.RFC3339Nano
	output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "2006-01-02 15:04:05.000000"}
	output.FormatLevel = func(i interface{}) string {
		return fmt.Sprintf("%-6s", i)
	}
	output.FormatMessage = func(i interface{}) string {
		return fmt.Sprintf(" %s ", i)
	}
	output.FormatFieldName = func(i interface{}) string {
		return fmt.Sprintf("%s:", i)
	}
	output.FormatFieldValue = func(i interface{}) string {
		return fmt.Sprintf("%s", i)
	}
	output.FormatCaller = func(i interface{}) string {
		t := fmt.Sprintf("%s", i)
		s := strings.Split(t, ":")
		if 2 != len(s) {
			return t
		}
		f := filepath.Base(s[0])
		return f + ":" + s[1]
	}
	zlog.Logger = zerolog.New(output).With().Timestamp().Caller().Logger()
	zlog.Info().Str("foo", "bar").Int("baz", 123).Msg("Hello World")
}

// 2019-01-20 18:48:25.743394 info   main.go:257  Hello World  baz:123 foo:bar
```

なお複数のpackageで構成するプログラムの場合にはglobal loggerを書き換えるよりもファイル先頭で

```go
var Logger zerolog.Logger
```

としておき、

```go
    Logger = zerolog.New(output).With().Timestamp().Caller().Logger()
    Logger.Info().Str("foo", "bar").Int("baz", 123).Msg("Hello World")
```

と設定して使う方が、packageごとに異なるログレベルを設定したりできるようになるので良さそうです。

### 使い方補足
zerologは本来機械可読な構造化ログを出力するためのものなので、表示したいパラメータは一つずつStr()やInt()といった型ごとのメソッドに名前と一緒に渡し、それをメソッドチェーンで繋ぐという思想の様です。自作のstructもInterface()で表示できます（リフレクションを使うので遅くはなるはずです）。

### 後づけの狙い
開発時にはログレベル付Loggerとして利用、出荷時にはPretty loggingをやめれば超高速Loggerであるzerologの恩恵にあやかれるはずだと思います。

### ログローテーション
[lumberjack](https://github.com/natefinch/lumberjack)を使うのが簡単そうです。

```go
writer := &lumberjack.Logger{
    Filename:   "/var/log/myapp/foo.log",
    MaxSize:    10, // megabytes
    MaxBackups: 5,
    MaxAge:     28, //days
    Compress:   true, // disabled by default
}
```

としておいて、

```go
output := zerolog.ConsoleWriter{Out: writer, ... 
```

これでできました。

※動作確認バージョン go 1.8.1 / zerolog v1.11.0
※当初[zap](https://github.com/uber-go/zap)を試そうとしましたが、最新2バージョンのみサポートだそうで、2019/1現在すでにgo 1.8.1では動きませんでした
cVim でページのタイトルとURLをコピー（リッチテキスト形式も）

cVim はVimライクなキーボード操作ができるようになるChromeの拡張です。
[cVim - Chrome ウェブストア](https://chrome.google.com/webstore/detail/cvim/ihlenndgcmojhcghmfjfneahoeklbjjh?hl=ja)

下記のような設定で、ページのタイトルとURLをコピーするキーバインドを定義できます。
自分はよくMarkdown形式でコピーします。便利。

```
" Clipboard Copy
copyText (text) -> {{
  Clipboard.copy(text);
  Status.setMessage('copied: ' + text, 2);
}}
copyUrl (format) -> {{
  let text = format.replace("%URL%", location.href).replace("%TITLE%", document.title);
  Clipboard.copy(text);
  Status.setMessage('copied: ' + text, 2);
}}
" copy markdown link
map cm :call copyText('['+document.title.replace(/([|\[\]])/g,'\\$1')+']'+'('+location.href+')')<CR>
" copy org link
map co :call copyText('[['+location.href+']['+document.title.replace(/([\[\]])/g,' ')+']]')<CR>
" copy textile link
map ct :call copyUrl('"%TITLE%":%URL%')<CR>
" copy title and url
map cu :call copyUrl("%TITLE% / %URL%")<CR>
" copy scrapbox link
map cs :call copyUrl('[%TITLE% %URL%]')<CR>
" copy href link
map ca :call copyUrl('<a href="%URL%">%TITLE%</a>')<CR>
```

こちらはリッチテキスト形式でリンクをコピーする関数。
`Range.selectNode()` と `document.execCommand('copy')` 使ったらできるかなと思い試したらできました。
WYSIWYGエディタやパワポにリンク貼り付けるときに使えます。

```
copyHtmlLink () -> {{
  var clipNode = document.createElement('a');
  var range = range = document.createRange();
  var sel = window.getSelection();
  clipNode.setAttribute('href', location.href);
  clipNode.innerText = document.title;
  document.body.appendChild(clipNode);
  range.selectNode(clipNode);
  sel.removeAllRanges();
  sel.addRange(range);
  document.execCommand('copy', false, null);
  document.body.removeChild(clipNode);
  Status.setMessage('copyHTMLLinkToClipboard',2);
}}

" copy html link
map cc :call copyHtmlLink()<CR>
```

[Qiita](https://qiita.com/) で実行してテキストエディットに貼り付けるとこんな感じです。
上がMarkdownで下がリッチテキスト形式。
<img width="161" alt="SS_ 2019-01-20 19.26.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/3464/aaa88329-ac63-8dbc-282a-c45e9cf05b37.png">


cVimの設定ファイルはこちらに置いています。
https://gist.github.com/hushin/f1a3d90b9db63026e798a90795733c6b

## 参考にした記事

- [VimperatorからVivaldi + cVimに乗り換えた - Qiita](https://qiita.com/nozma/items/c6bcebdffe35881dfd7a)
- [vimperatorの代替としてcVim入れてみた - Qiita](https://qiita.com/Jey/items/2bee3597bfc24fc8a1f8)
os.chdir()の移動をローカルにする

# 結論
デコレータを使い元のカレントディレクトリをセットし直す！

# 背景
Pythonでファイル処理をしていると、関数内でディレクトリ移動したくなる時があると思います。

しかし、関数内で`os.chdir`を使うと、スコープを抜けてもカレントディレクトリは戻りません。

```python:sample.py
import os

def move_dir():
    os.chdir('fuga')
    print(os.getcwd())

if __name__ == '__main__':
    print(os.getcwd())
    move_dir()
    print(os.getcwd())
```

```:結果
.../hoge
.../hoge/fuga
.../hoge/fuga
```

カレントディレクトリを戻すためには、関数内で最初にカレントディレクトリを変数に保持し、
最後にもう一度元のディレクトリに移動する必要があります。

```python
def move_dir():
    dir = os.getcwd()
    os.chdir('fuga')
    print(os.getcwd())
    os.chdir(dir)
```

ちょっと見栄えが悪いですね…

# そうだ デコレータ、使おう
「前後に決まった処理をする」と言えばデコレータです。
という訳で、最後にカレントディレクトリを元に戻すデコレータを作りました。
以下の`local_chdir`を使えばディレクトリ移動を（実質）ローカルにできます。

```python:local_chdir.py
import os

def local_chdir(func):
    def _inner(*args, **kwargs):
        # 元のカレントディレクトリを変数に代入
        dir_original = os.getcwd()
        # 渡された関数実行
        ret = func(*args, **kwargs)
        # カレントディレクトリを元に戻す
        os.chdir(dir_original)
        return ret
    return _inner

@local_chdir # デコレータ
def move_dir():
    os.chdir('fuga')
    print(os.getcwd())

if __name__ == '__main__':
    print(os.getcwd())
    move_dir()
    print(os.getcwd())
```

```:結果
.../hoge
.../hoge/fuga
.../hoge
```

これで、関数内のディレクトリ移動を気にする必要がなくなりました！
php-master-changes 2019-01-19

今日はカレントディレクトリが無効なディレクトリな時に realpath() に '.' とか './' を渡すとクラッシュする問題の修正、imagewbmp() が巨大画像に使われた時 SEGV が起きる問題の修正、libgd の上流のバグ修正取り込みがあった！

# 2019-01-19
## weltling: Fixed bug [#77484](https://bugs.php.net/bug.php?id=77484) Zend engine crashes when calling realpath in invalid working dir
- https://github.com/php/php-src/commit/8b20e7b68bd81ab74423c9f7937699f79401cec4
- [7.3~]
- カレントディレクトリが無効なディレクトリのときに '.' とか './' で realpath() を呼ぶとクラッシュする問題の修正

## weltling: Make test output more reliable
- https://github.com/php/php-src/commit/4254bf87bac5f79524eea48f1b53efbb2459840b
- [7.3~]
- ↑のテストを修正
- 出力コードを 1 箇所にまとめてどの変数がどの出力に対応するか分かりやすくしたような感じか？と思うもののそんなに意図分かってはおらず

## cmb69: Fix [#77479](https://bugs.php.net/bug.php?id=77479): imagewbmp() segfaults with very large images
- https://github.com/php/php-src/commit/44fa0b0f311beee4bfcbdb954d61f0c9a8395a96
- [7.2~]
- ext/gd で、[imagewbmp()](http://php.net/manual/ja/function.imagewbmp.php) が巨大画像に使われた時 SEGV が起きる問題の修正

## cmb69: Fix failing test
- https://github.com/php/php-src/commit/2966da70cf10db8b3213513850bbb74931c08e6c
- [7.3~]
- ↑の修正のテストこけを修正

## cmb69: Sync with upstream
- https://github.com/php/php-src/commit/089f7c0bc28d399b0420aa6ef058e4c1c120b2ae
- ext/gd で、[libgd 側のバグ修正](https://github.com/libgd/libgd/issues/492)に追従
- PHP では使ってない奴らしく不要だが、一応 upstream に同期しとこうという感じらしい

## weltling: Skip test on unsuitable build
- https://github.com/php/php-src/commit/52730fa30a848eabfcb02abea30446ef657a0f01
- [7.3~]
- [#77484](https://bugs.php.net/bug.php?id=77484) の[修正](https://qiita.com/drafts/121fdfefbbde68795c34/edit#weltling-fixed-bug-77484-zend-engine-crashes-when-calling-realpath-in-invalid-working-dir)について、テストを ZTS 版ではスキップするよう修正
- 非スレッドセーフ版ではシステムの getcwd() が使われ、 スレッドセーフ版では fake 版が使われるので、このへん挙動に違いが出るらしい
tensorflow.jsで自動運転

#概要

tensorflow.jsで自動運転、やってみた。

#写真

![](http://jsdo-static-contents.s3.amazonaws.com/images/capture/m/L/2/mL26.jpg?t=1547977636)

#仕組み

画面下の五つのグレーのポイントで、センサーとして、rgb/256/3で、データを取った。
1000個のデータセットを作った。
tensorflow.jsでモデルを作って、学習させた。
モデルは、インプット5、アウトプット3の分類器、
隠れ層は、20
アクチベーションは、sigmoid
オプチマイザーは、adam
学習は、3000回。
正解率は、54.0％

#成果物

http://jsdo.it/ohisama1/mL26

以上。
【Golang】参照型Mapについて

Go勉強中のgataponです。
参照型のMapについてアウトプットも兼ねて投稿します。


## Map

PHPの連想配列と同じで、`キー値`:`要素値`の構造をしています。


### Mapの生成

```golang

drink := map[int]string {
    1: "coffee",
    4: "tea",
    8: "wine",
}

fmt.Println(drink) 
// map[1:coffee 4:tea 8:wine]

fmt.Println(drink[4])
// tea

fmt.Println(drink[2])
// ""
// 出力される
```

### 要素を追加と削除

要素の追加は`変数[指数]`を指定して追加。
`:=`は変数宣言の時なので必要ない。<br>

既に`キー値`がある場合は上書き。

```golang:追加
// 要素を追加
m[2] = "green_tea"
fmt.Println[(drink[2])
// green_tea
```

```golang:削除
drink := map[int]string {
    1: "coffee",
    4: "tea",
    8: "wine",
}

delete(drink, 1)

fmt.Println(drink)
// map[4:tea 8:wine]
```

### for を使ったMap表示

```golang
// for range使う
for v, k := for range {
    fmt.Printf("%d => %s\n", v, k)
}
// 0 => coffee
// 1 => tea
// 2 => wine
```

### Mapにネストさせる

Mapに配列のネスト

```golang
m := map[int][]string {
    1: []string{Ruby, PHP, JavaScript}
    2: []string{Cat, Dog, Monkey}
    3: []string{Tokyo, Osaka, Kyoto, Aichi}
}

fmt.Println(m[3][0])
// Tokyo
```
GolangのGORMで単数形のテーブルを扱う

GolangのORMの [GORM](https://github.com/jinzhu/gorm) はRailsのActiveRecord影響を受けているのかテーブル名は複数形であることを要求されます。
モデル名は単数、DBのテーブルは複数形という文化に慣れていないと混乱するし、既存のプロジェクトに `GORM` を導入する際の障害になりかねません。
ここでは `GORM` で単数形のテーブルを扱うための方法を紹介します。

## 前提条件
以下の環境で動作を確認しています。

* Go 1.11.1
* GORM 1.9.1
* PostgreSQL 9.6.9

## 単数形のテーブルを扱うための二つの方法
### 1. db.SingularTable(true)

```go
db.SingularTable(true)
```

DBの初期化時などに `gorm.DB` に対して上記のコードを実行します。
これは破壊的操作かつ、これ以降でこの `db` オブジェクトが発行する全てのDB操作に影響します。

例えば、以下のようなモデルを定義している場合は `samples` ではなく `sample` テーブルが対象になります。

```go
type Sample {
  gorm.Model
}

var sample Sample
db.First(&sample) // sampleテーブルにSELECT文を発行する
```

`モデル名 = テーブル名` という命名ルールで開発を行いたい場合にはこの方法がシンプルでよいかと。

### 参考情報: SingularTableの実装
```go
// main.go
func (s *DB) SingularTable(enable bool) {
	modelStructsMap = sync.Map{}
	s.parent.singularTable = enable
}
```

[DB.SingularTableの実装へのリンク](https://github.com/jinzhu/gorm/blob/master/main.go#L172-L175)

### 2. DB操作毎にテーブル名を指定する
単数形のテーブルに対するDB操作毎に `db.Table` を呼び出してテーブル名を明示的にセットする方法です。
都度指定する手間がありますが他のDB操作には影響しないので一部のテーブルだけが単数形の名称の場合には有用な方法です。
`db.Table` を呼び出す以外は `GORM` の操作方法は変わりません。

```go
type Sample {
  gorm.Model
}
```
```go
sample := Sample{}
db.Table("sample").Create(&sample)
```
```go
var sample Sample 
db.Table("practice").Order("id").First(&sample)
```

### 参考情報: 
```go
// main.go
func (s *DB) Table(name string) *DB {
	clone := s.clone()
	clone.search.Table(name)
	clone.Value = nil
	return clone
}
```

クローンを生成して返しているので元のDBオブジェクトには影響を与えません。

[DB.Tableの実装へのリンク](https://github.com/jinzhu/gorm/blob/master/main.go#L485-L490)

## 参照実装
上記を踏まえて `GORM` を利用したサンプルコードを公開しているので参考にしてください。

https://github.com/cobot00/gorm-practice/blob/master/main.go
ExpoのAndroidエミュレータでNoxを使用する

# 前提

- Mac Os X
- expo 31.0.0
- Android Studioインストール済
 - adb(Android Debug Bridge)コマンドが使用可能。
- Nox 1.2.6.0

# 1. Noxをインストール
下記よりNoxをインストールする。
https://jp.bignox.com/

# 2. Noxの設定
 1. Nox起動後、右上の歯車を押す。
<img src="https://qiita-image-store.s3.amazonaws.com/0/337390/ab01cb09-724c-6efa-0992-c238ff9aa477.png" width="50%"/>


 1. ROOTをオンにする。適宜、メモリや画面サイズを変更する。
 1. 設定を保存。（再起動される。）
<img src="https://qiita-image-store.s3.amazonaws.com/0/337390/211a1c1f-2abb-910e-17d7-020c5e257c4a.png" width="50%"/>

# 3. Androidの設定
 1. 右下の「設定」を押す。
<img src="https://qiita-image-store.s3.amazonaws.com/0/337390/2704d53f-422a-abe5-87ae-e72003737471.png" width="50%"/>

 2. 一番下の「タブレット情報」を押す。
 3. 一番下の「ビルド番号」を"これでデベロッパーになりました！"と表示されるまで連打する。
 4. 前の画面(設定)に戻り「開発者向けオプション」を押す。
 5. 「USBデバッグ」をONにする。
<img src="https://qiita-image-store.s3.amazonaws.com/0/337390/268dc0cc-c7e7-3c86-0c91-b55d9eb9e9f9.png" width="30%"/>

# 4. 接続
下記のadbコマンドで接続する.
`adb connect 127.0.0.1:62001`

# 5. 実行
下記のコマンドを実行後、アプリをNoxにて実行する。
`expo start`


以上。
Arduino(ATmega328P)と加速度センサーで地震計を作ってみる

この週末は、Arduino(というかATmega328P)と加速度センサ(KXR94-2050)を組み合わせて、地震計を作ってみた。
そもそものきっかけは[「Raspberry Pi 簡易震度計」](https://www.p2pquake.net/dev/rpi_seismometer/)というページで、Raspberry Piと加速度センサの組み合わせで地震計を実現しているのを見て、ESP32あたりのほうがいいんじゃないのと思い、実験してみたくなった。
いきなりESP32というのも手間なので、まずはATmega328P-PU単体(内蔵8MHzオシレータ)で試してみたので、そのメモ。

まず、USB Serialを5Vの電源にし、KXR94のX,Y,Z三軸の出力を328PのA3,A4,A5入力とつなぎ試した。データを取得したところ、まったく動かない状態でも、ノイズだけで数Gal程度。つまり震度2程度揺れている感じでとてもじゃないが地震計にはならない。

USB Serialの電源を3.3Vにしたところ、USB Serialのレギュレータで安定化されるのか少し良くなった。更に電源に数十μFの電解コンデンサを入れてみてやっとノイズが1.5Gal、つまり震度1程度。三軸出力に0.1μFの積層セラミックコンデンサを三つ入れてみたが、あまり効果なかった。

よく考えると、センサで取得できる範囲は5G = 4900Gal (Gal = cm/s/s)で、それを10bitのA/Dコンバータ、つまり0-1023の数字に変換している。だから、量子化ノイズだけで数Galは発生しうるわけで、いくら数値処理をしたところで1Gal以下、つまり震度1未満を取得するのは難しいのかもしれない。

とりあえず作ったプログラムをgithubに置いてみる。また何か思いついたら、いじってみよう。
[https://github.com/toyo/KXR94-2050](https://github.com/toyo/KXR94-2050)
Ubuntu Server 18.04 on ESXi 6.5 で GeForce 1080ti をパススルーすーるー

# 概要

ESXi 6.5上にUbuntuServer18.04を構築して、GeForce1080tiをパススルーで設定し、Nvidiaのドライバを入れたのでその手順。（備忘録）
Nvidiaのドライバをインストールすることにフォーカスしているので、Ubuntuの構築やパススルーは省略。

# 構成
- ESXi 6.5
- Ubuntu Server 18.04
- GeForce 1080ti

# 手順
UbuntuServerを構築して、[ここ](https://taktak.jp/2018/05/01/2974)を参考にドライバをインストール。
しかしインストール状況が確認ができない。

```` 
$ nvidia-smi
Unable to determine the device handle for GPU 0000:03:00.0: Unknown Error
````

ググったら原因はESXiの設定だったらしい。[ここ](https://devtalk.nvidia.com/default/topic/982322/linux/nvidia-smi-reports-unable-to-determine-the-device-handle-for-gpu/)を参考にして、VMの設定を変更。

変更手順は
1. ESXiでVMを選択し、「設定の編集」をクリック
2. 設定画面で「仮想マシン　オプション」タブに切り替える
3. 「詳細」の「構成を編集…」をクリック
4. 構成パラメータにキーを「hypervisor.cpuid.v0」、値を「FALSE」に設定。（ない場合は新規追加）

これで確認ができた。
tarの圧縮は速いほうがいいよね

「tarでバックアップ取る運用はやめろよ」という愚痴はおいといて、tarは速い方がいいですよね。

## Environment
* CentOS Linux release 7.3.1611 (Core)

## tarのzオプション

tarの zオプションは内部でgzipを呼んでいるだけだよね。

```
$ strace -f -e execve tar czf hoge.tgz ./apache-tomcat-9.0.14
execve("/bin/tar", ["tar", "czf", "hoge.tgz", "./apache-tomcat-9.0.14"], [/* 22 vars */]) = 0
Process 5717 attached
[pid  5717] execve("/usr/local/bin/gzip", ["gzip"], [/* 22 vars */]) = -1 ENOENT (No such file or directory)
[pid  5717] execve("/bin/gzip", ["gzip"], [/* 22 vars */]) = 0
[pid  5717] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5717, si_status=0, si_utime=67, si_stime=2} ---
+++ exited with 0 +++
```

## gzipの圧縮オプション

個人的な価値観では``--best``より``--fast``がいいです。
gzipのmanページによると、GZIP環境変数があるらしい。

```
This  option can be set in the GZIP environment variable as in:
   for sh:  GZIP="-q"  tar -xfz --block-compress /dev/rst0
   for csh: (setenv GZIP -q; tar -xfz --block-compr /dev/rst0
```

tarにはgzipやbzip2の圧縮レベルオプションはないけど、この環境変数を使えばtarのzオプションで圧縮レベルを設定できるということですね。

```bash
$ time  tar czf hoge1.tgz ./apache-tomcat-9.0.14

real    0m0.662s
user    0m0.647s
sys     0m0.043s

$ export GZIP=-1
$ time  tar czf hoge2.tgz ./apache-tomcat-9.0.14

real    0m0.549s
user    0m0.536s
sys     0m0.031s

$ du -sh apache-tomcat-9.0.14 hoge1.tgz hoge2.tgz
16M     apache-tomcat-9.0.14
10M     hoge1.tgz
11M     hoge2.tgz
```

アーカイブ作成時間は速くなっています。やりぃ。
圧縮率が少々ぬるいのはトレードオプなので仕方がないですね。


## もっと速くしたい

もっと速くアーカイブを作りたいなら、gzipよりlzopですよね。
lzopのmanをみるとLZOPというオプションがあるようだ。

```
The environment variable LZOP can hold a set of default options for lzop. These options are interpreted first
and can be overwritten by explicit command line parameters.  For example:

    for sh/ksh/zsh:    LZOP="-1v --name"; export LZOP
    for csh/tcsh:      setenv LZOP "-1v --name"
    for DOS/Windows:   set LZOP=-1v --name
```


CentOS7のtarのmanページはないけど、``--use-compress-program``というオプションがあるようだ。
LZOP環境変数を設定して、lzopにてフィルタ圧縮をしてみる。

```
$ export LZOP="-1 --name"
$ time tar --use-compress-program=lzop -cf hoge-lzop.tar.lzo ./apache-tomcat-9.0.14

real    0m0.050s
user    0m0.028s
sys     0m0.024s
```

これは圧倒的な速さだ。
じゃあ、lz4でもいけるのかな、と思ったのだけど、lz4にはオプション設定する環境変数は見つからない。
とりあえずデフォルトモードで実行してみる。

```
$ time tar --use-compress-program=lz4 -cf hoge-lzop.tar.lz4 ./apache-tomcat-9.0.14

real    0m0.055s
user    0m0.037s
sys     0m0.019s
```

これも圧倒的な速さだ。

いろいろコマンドを組み合わせれるのは良いですね。