OmniAICreator/Qiita-1.07M huggingface dataset:
iPhoneのUnityゲームで短い・弱い振動（バイブレーション）をさせる方法

#目標
Unityのゲームで一定の場合には（例えば、GameObjectの衝突が発生した場合）iPhoneを短くかつ弱く振動させることです。
Unityの「[Handheld.Vibrate()](https://docs.unity3d.com/ScriptReference/Handheld.Vibrate.html)」を簡単に使ったらバイブレーション自体はできますが、振動の強さ・長さ・種類は一切調整できないため（実機でテストしてみたら、結構強い振動でした。:skull_crossbones:）、必ずほかの方法を見つけないといけません。
#解決方法
iOSは、AudioToolbox.frameworkのAudioServicesでさまざまな[効果音](http://iphonedevwiki.net/index.php/AudioServices)とバイブレーションを用意してくれています。

しかし、Unityから直接にiOSのAudioServicesを呼び出すことがまだ不可能らしいので、「[iOS用のプラグインをビルド](https://docs.unity3d.com/ja/current/Manual/PluginsForIOS.html)」という方法で間接的に呼び出せるようにします。

手順は以下の通りです。（もう自分のUnityゲームで実装済み）
###①Object-CのスクリプトplaySystemSound.mmを作成します。
```objective_c
#import <Foundation/Foundation.h>
#import <AudioToolBox/AudioToolBox.h>

extern "C" void playSystemSound (int n)
{
    AudioServicesPlaySystemSound(n);
}
```
*名前はplaySystemSoundじゃなくても何でも可。言語はObject-CじゃなくてC++（.cpp）でも問題無さそうだけど、未検証のため、ご興味のある方は自分で試してみてください。*
###②作成したplaySystemSound.mmファイルをUnityのAssetsフォルダの下に置きます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/305759/bb38d377-77d1-ba93-6d79-0189c38c8f63.png)
*Assetsフォルダーの下ならどこでも可。*
###③UnityのC#スクリプトにplaySystemSoundメソッドを呼び出すコードを作成します。
自分のゲームのプログラムを例として説明します。
GameObject「Target」の衝突があった時にiPhoneを振動させるとします。
まず、「Target」には「TargetController.cs」というC#スクリプトをアタッチします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/305759/2535650d-ff40-3d96-e6c3-d107c46023ad.png)
Targetの衝突があった時、Unityが自動的にOnTriggerEnter関数を呼び出すので、「振動させる」コードをOnTriggerEnterの中に書くとよいでしょう。

```c#
public class TargetController : MonoBehaviour
{
    /* ほかのコード略 */ 
    [DllImport("__Internal")]
    private static extern void playSystemSound(int n);
    /* ほかのコード略 */  
    private void OnTriggerEnter(Collider other)
    {
       /* ほかのコード略 */ 
       #if UNITY_EDITOR
       Debug.Log("Play system sound or vibration on real devices");
       #else
       playSystemSound(1519);
       #endif
       /* ほかのコード略 */ 
    }
```
*ここで* **注意** *していただきたいのは、もし、Unity EditorでplaySystemSoundを呼び出すと、下記のような「EntryPointNotFoundException」が出てしまうのです。* **iPhone実機で実行するとそういうExceptionは出ない** *ので、「#if UNITY_EDITOR」([プラットフォーム依存コンパイル](https://docs.unity3d.com/ja/current/Manual/PlatformDependentCompilation.html))を使ってUnity Editorの場合を外したほうが無難です。*
![image.png](https://qiita-image-store.s3.amazonaws.com/0/305759/43d90f68-edb8-b92a-2b08-9ebce92a0220.png)
*なお、playSystemSound(int n)のパラメータ「n」は、* **「1519」** *を使うと* **「プッ」という短い・弱いバーブレーション** *になります。*

*別途で「1005」を試してみました。iPhoneをミュートするとシステムアラームの振動と同じようなバイブレーションが出ました。逆にiPhoneをunmuteするとvibrationが出なくてアラームの効果音だけが出ました。*
*ほかのパラメータについて、ご興味のある方自分で試してみてください :point_right: [iOS Predefined sounds](http://iphonedevwiki.net/index.php/AudioServices)*

以上です。
Audiophile Linux: NetworkManager を利用した IP アドレス固定手順

## dhcpcd 停止, 自動起動無効化

```bash
sudo systemctl status dhcpcd -l
sudo systemctl stop dhcpcd
sudo systemctl disable dhcpcd
sudo systemctl status dhcpcd -l
```


## NetworkManager 自動起動有効化, 起動

```bash
sudo systemctl status NetworkManager -l                                                                                                                                                                            :(
sudo systemctl enable NetworkManager
sudo systemctl start NetworkManager
sudo systemctl status NetworkManager -l
```


## 既存設定削除

- SSH 接続が切れるため, コンソール上で実行した方が無難。


1. `% LANG=C sudo nmtui` を実行し, NetworkManager TUI を起動する。
1. **Edit a connection** を選択する。
1. **Delete** を選択し, **全て** の Ethernet を削除する。
1. **Back** を選択し, メニューに戻る。
1. **Quit** を選択し, NetworkManager TUI を終了する。
1. `% sudo systemctl reboot` を実行し, OS を再起動する。


## IP アドレス固定化

1. `% sudo nmcli c show` を実行し, 編集する ethernet の UUID を確認する。
1. `% sudo nmcli -f ipv4 c show <UUID>` を実行し, 現在の設定値を確認する。
1. `% sudo nmcli c modify <UUID> ipv4.method "manual" ipv4.addresses "<address>/<prefix>" ipv4.gateway "<gateway>" ipv4.dns "<dns-server>" ipv4.dns-search "<dns-search>"` を実行する。
   - UUID: 先ほど確認した ethernet の UUID。
   - ipv4.addresses: 設定する IPv4 アドレス。ネットマスクは CIDR 形式で指定する。
   - ipv4.gateway: デフォルトゲートウェイの IPv4 アドレス。
   - ipv4.dns: 参照先 DNS サーバーの IPv4 アドレス。
   - ipv4.dns-search: 名前解決時に付与するドメイン名。
1. `% sudo nmcli -f ipv4 c show <UUID>` を実行し, 設定後の設定値を確認する。
1. `% sudo systemctl reboot` を実行し, OS を再起動, 固定化した IP アドレスが設定されていることを確認する。


どっとはらい。
render partial collectionのドキュメントを試した

部分テンプレートをcollectionと一緒に利用する時に、ドキュメントを読んだら色々と出来ることが分かったのでメモ

## 1. 基本的な使い方

` <%= render partial:"ad", collection: @ads %> `
 
呼出元のerbファイルと同じディレクトリにある _ad.html.erb テンプレートに、adsの各要素を adというローカル変数にして受け渡す

ということ。大体ここまでしか書いていない解説が多かったのですが、 APIドキュメントを見ると色々と便利なことが出来ることが分かりました

https://api.rubyonrails.org/　で、キーワード PartialRenderで検索して出てきたドキュメント
https://api.rubyonrails.org/classes/ActionView/PartialRenderer.html
を参照にしています

## 2. テンプレートで使う変数名をファイル名とは関係なく設定する

` <%= render partial:"application/ad_view_parts", collection: @ads, as: ad %> `

こんな感じで、汎用的にapplicationフォルダの中に、_ad_view_parts.html.erb というテンプレートを作って表示させる。
でも、テンプレートの中で使っている変数は ad_view_partsでは無く、adにしたい。
ということが出来ます

## 3. collection以外に変数を渡したい。

他の解説書を見ると、テンプレートは特定のモデルオブジェクトに対応させるべきで、渡す引数はモデルオブジェクトだけで充分であることが望ましい。

とか述べているところが多いです。

とは言うものの、テンプレートに遷移元のページタイトルとか、モデルから取得出来ない項目を使いたいこともあります。

こちらは、local:{}オプションを受け渡すことで上手くいきました。collectionと両立出来るのですね。。

` <%= render partial:"application/ad_view_parts", collection: @ads, as: ad, locals:{caller_title: page_title, page_status: "new"} %> `

## 4. collectionの何番目なのかをテンプレート中から取得したい

```
<% num=0 %>
<% @ads.each do |ad| %>
<% num += num %>
<%= "#{num}番目の広告:#{ad.title}" %>
<% end %>
```

とか言うようなことをやっていました、do ～ endの部分をtemplateかしていた感じです。が
テンプレートの中から参照出来る変数 ad_iteration というのが自動で割り当てられるとのこと。

試しに、 ` p ad_iteration ` として確認すると

```
#<ActionView::PartialIteration:0x00007f2da8418f20 @size=1, @index=0>
```
こんなプロパティがあるとのこと、なので、上の例は

```
render "_ad_view_parts", collection: @ads, as: ad
```

と _ad_view_parts.html.erbファイルとして

```
<%= "#{ad_iteration.index+1}番目の広告:#{ad.title}" %>
```

と記述出来る。
その他, first?, last?というメソッドも、**_iteration にはあるらしいです
sysstat(sar)の採取間隔を10分から1分に変更する方法

# 対応
cronの記載を変更するだけで対応

- 変更前

```
*/10 * * * * root /usr/lib64/sa/sa1 1 1
```

- 変更後

```
*/1 * * * * root /usr/lib64/sa/sa1 1 1
```
GentooLinux に docker を入れる

## 環境

Windowsで動くVirtualBox上のGentooLinux(systemd使用)

## 手順概略

1. app-emulation/docker を emerge する
1. dockerグループにいつも使うユーザーを追加する
1. kernel のオプションが諸々必要らしいので kernelを再構築する
1. 再起動して systemctl start docker
1. 具合良ければ systemctl enable docker

## 手順

dockerという名前はいくつかあるので、app-emulationを指定しないと入らない。

```shell
$ sudo emerge -av app-emulation/docker
```

手前の環境だと12個くらいの依存の元何の問題もなく入る。
docker グループにユーザーを追加するといいよ、と後はカーネルオプション諸々を有効にする旨表示されるのでそれに従う。

```shell
$ sudo gpasswd -a <user> docker
```

```shell
# カーネルのバージョン確認。手間の環境の場合新しくなっていた。。
$ eselect kernel list
Available kernel symlink targets:
  [1]   linux-4.14.65-gentoo *
$ sudo eselect kernel set 1
$ cd /usr/src/linux
$ sudo make menuconfig
...
$ sudo make
$ sudo mount /boot
$ sudo make modules_install && make install
$ sudo grub-mkconfig -o /boot/grub.cfg
$ subo reboot
```
で一旦再起動。

```shell
$ sudo systemctl start docker
```
で問題なく起動できたら

```shell
$ sudo systemctl enable docker
```
としておく。

有効にするらしいカーネルのオプションはemerge時に書いてあったけど改めてメモ。
たくさんあるので、menuconfigで探しながら有効にしていきましょう。。。

```
 *  - NAMESPACES
 *  - NET_NS
 *  - PID_NS
 *  - IPC_NS
 *  - UTS_NS
 *  - CGROUPS
 *  - CGROUP_CPUACCT
 *  - CGROUP_DEVICE
 *  - CGROUP_FREEZER
 *  - CGROUP_SCHED
 *  - CPUSETS
 *  - MEMCG
 *  - KEYS - CONFIG_KEYS: is mandatory
 *  - VETH
 *  - BRIDGE
 *  - BRIDGE_NETFILTER
 *  - NF_NAT_IPV4
 *  - IP_NF_FILTER
 *  - IP_NF_TARGET_MASQUERADE
 *  - NETFILTER_XT_MATCH_ADDRTYPE
 *  - NETFILTER_XT_MATCH_CONNTRACK
 *  - NETFILTER_XT_MATCH_IPVS
 *  - IP_NF_NAT
 *  - NF_NAT
 *  - NF_NAT_NEEDED
 *  - POSIX_MQUEUE
 *  - USER_NS
 *  - SECCOMP
 *  - CGROUP_PIDS
 *  - MEMCG_SWAP - CONFIG_MEMCG_SWAP: is required if you wish to limit swap usage of containers
 *  - MEMCG_SWAP_ENABLED
 *  - BLK_CGROUP - CONFIG_BLK_CGROUP: is optional for container statistics gathering
 *  - BLK_DEV_THROTTLING
 *  - IOSCHED_CFQ - CONFIG_IOSCHED_CFQ: is optional for container statistics gathering
 *  - CFQ_GROUP_IOSCHED
 *  - CGROUP_PERF - CONFIG_CGROUP_PERF: is optional for container statistics gathering
 *  - CGROUP_HUGETLB
 *  - NET_CLS_CGROUP
 *  - CFS_BANDWIDTH - CONFIG_CFS_BANDWIDTH: is optional for container statistics gathering
 *  - FAIR_GROUP_SCHED
 *  - RT_GROUP_SCHED
 *  - IP_VS
 *  - IP_VS_PROTO_TCP
 *  - IP_VS_PROTO_UDP
 *  - IP_VS_NFCT
 *  - IP_VS_RR
 *  - VXLAN
 *  - CRYPTO
 *  - CRYPTO_AEAD
 *  - CRYPTO_GCM
 *  - CRYPTO_SEQIV
 *  - CRYPTO_GHASH
 *  - XFRM_ALGO - CONFIG_XFRM_ALGO: is optional for secure networks
 *  - XFRM_USER - CONFIG_XFRM_USER: is optional for secure networks
 *  - IPVLAN
 *  - MACVLAN
 *  - DUMMY
 *  - CGROUP_NET_PRIO
 *  - BLK_DEV_DM
 *  - DM_THIN_PROVISIONING
 *  - EXT4_FS
 *  - EXT4_FS_POSIX_ACL
 *  - EXT4_FS_SECURITY
 *  - OVERLAY_FS
 *  - EXT4_FS_SECURITY
 *  - EXT4_FS_POSIX_ACL
 ```

## トラブル

kernelのオプションを有効にしたものの make install を忘れてkernelが更新されてなかったときに出ていたエラー。
解決まで無駄に時間がかかってしまった。。。

> level=error msg="[graphdriver] prior storage driver devicemapper failed: devicemapper: Error running deviceCreate (CreatePool) dm_task_run failed"
ずんだの表見出し++問題 Ruby 編

## プログラム（Ruby）
```ruby
DATA.each_line.map do |e|
  row = e.split('|')
  row[0] = row[0].to_i + 1
  print row.join('|')
end

__END__
0|col1|col2|col3
1|col1|col2|col3
2|col1|col2|col3
3|col1|col2|col3
4|col1|col2|col3
```

## 出力
```
1|col1|col2|col3
2|col1|col2|col3
3|col1|col2|col3
4|col1|col2|col3
5|col1|col2|col3
```

* [ずんだ問題まとめ - Qiita](https://qiita.com/tbpgr/items/3a4169b370f1a317ece0)
AfterEffects エフェクト例 背景素材

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">For Example<br><br>詳細はこちら<a href="https://t.co/3DoROexONI">https://t.co/3DoROexONI</a> <a href="https://t.co/HBeD6cXDu6">pic.twitter.com/HBeD6cXDu6</a></p>&mdash; YouTool (@YouTool3) <a href="https://twitter.com/YouTool3/status/1054647569710632960?ref_src=twsrc%5Etfw">2018年10月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


平面レイヤーにParticularを追加
エフェクト名■Particular
パラメーター▶Particles/sec
変更値▶200
パラメーター▶Emitter Type
変更値▶2
パラメーター▶Position Z
変更値▶1420
パラメーター▶Emitter Size X
変更値▶2417
パラメーター▶Emitter Size Y
変更値▶1280
パラメーター▶Particle
パラメーター▶Life [sec]
変更値▶2
パラメーター▶Size
変更値▶0.2
パラメーター▶Physics
パラメーター▶Motion Path
変更値▶2
パラメーター▶Spin Amplitude
変更値▶100
パラメーター▶Spin Frequency
変更値▶7.50000000000001
パラメーター▶Turbulence Field
パラメーター▶Emit
変更値▶3
パラメーター▶Particles/sec
変更値▶484
パラメーター▶Life [sec]
変更値▶3
パラメーター▶Size
変更値▶0.5
パラメーター▶Color From Main [%]
変更値▶100
エフェクト名■グロー
パラメーター▶グローしきい値
変更値▶161
パラメーター▶グロー半径
変更値▶40
オブジェクト指向を学ぶ前に学びたい「哲学、設計、実装、指標、パターン」

# はじめに

## 動機

 オブジェクト指向についての記事がたくさんありますが、
「結局なんだかよくわからん」となっている人が多そうなので、
そんな人たちの道しるべになればなーと思って書きました。

## 内容

オブジェクト指向を学ぶ人にとって「なんもわからん」になる理由、

それは
「**プログラムの知識というより、問題解決の姿勢や理念** (の集積)」
「**オブジェクト指向とは、その理念に基づいて複数のフェーズが織りなす複合的な技術**」
であるということが伝わっていないことだと思います。

そこで、この記事では「オブジェクト指向を学ぶ」より前に、
関連する情報を整理する「知識の置き場所」を作る事を目指して、
主に分類を目的に書いています。


### 分類について

ただし、この分類は一般的なものではなく、
定義についてもより良いものがあるかもしれません。
アドバイスなどがあれば、お気軽にコメントなどをいただけると助かります。

また、分類それぞれに合わせて、
調べるためのキーワードを載せていますので、足掛かりにしてください。

# ５種類の視点

## オブジェクト指向の哲学

哲学というと大げさに見えるかもしれませんが、
「どうしてオブジェクト指向という言葉ができたか」
「それが何を目指していたのか」
こうした背景の知識や精神を哲学として分類したいと思います。

もしあなたが「サクッと使いたいだけなんだ」と思っても、
まずは焦らずにこうした知識に触れてください。

オブジェクト指向は優れた「問題解決の手法」ですが、
魔法の道具ではありません。
使い方を知らなければ、ナイフの刃を自分で握るような事態になります。

大まかなキーワードは以下のようなものがあります。

- 柔軟性
- 大規模開発 
- 構造化・モデル化
- 抽象化・パターン化
- 振る舞いの隠蔽とモジュール化
- メッセージング・相互作用
- C++
- Smalltalk

## オブジェクト指向の設計

哲学として、
どのような場面でオブジェクト指向を使うべきかを学んだあとは、
特性を生かす場面で適用させていくことになります。
その運用を考えるのが設計です。

もしあなたが急いでいるとしても、
「オブジェクト指向は現実の物体（オブジェクト）を扱うような～」という説明を信じているなら、
もう少し哲学に関心を持ってから設計に入ったほうが良いかもしれません。
オブジェクトが「物体」であるという固定概念は、目的である柔軟性からほど遠いものです。

大まかなキーワードは以下のようなものがあります。

- 関心の分離
- 単一責任
- インタフェース
- 依存性の管理
- UML （Universal Modeling Language)

## オブジェクト指向の実装

オブジェクト指向のプログラミングにおいて、
実装はその設計を実現する手段にすぎません。

チームメンバーが正しくオブジェクト指向を理解し、
それを全員で推進できるなら、
特別な言語や実装技術に依存する要素はほとんどなくなります。

また、どれほど優れたプログラマーでも、
オブジェクト指向に根差していない設計の上では、
オブジェクト指向を実現することはまず不可能です。

とはいえ、オブジェクト指向を進める手助けとして、
以下のような知識や技術を持っておくと、
作業効率が大きく上がることは間違いありません。
人力に頼らなくてよいようにするために、自動化があるのです。

大まかなキーワードは以下のようなものがあります。

- カプセル化
- 継承と包含
- 名前
- 副作用
- 高階関数と関数合成

## オブジェクト指向のパターン

オブジェクト指向の特徴をよりよく生かすためには、
ときに「天才的なひらめき」が必要になることがあります。
しかし誰にでもそれができるわけではありません。

そこで、オブジェクト指向を実践してきたエンジニアや研究者たちが、
様々なプログラムで効果的だった・よく使われる手法を、
パターンとして残してくれていますので、使わせてもらいましょう。

なお、具体的なパターンには以下のようなものがあります。
概要については独自のもので、
「何を目的としてパターンが生まれたのか」を表しています。
もし間違いがあればご指摘ください。

| パターン名 | 概要 |
| --- | --- |
| Chain of Responsibility pattern | 処理責任の分割 |
| State pattern |分岐の隠蔽と処理実装の分割 |
|Decorator pattern | インスタンスの機能と実装の分割 |

| パターン名 | 概要 |
| --- | --- |
| Observer pattern | 状態管理の分離 |
| Facade pattern| インスタンス管理の分離 |
| Proxy pattern | 要求処理、対象管理の分離 |
| Command pattern |要求詳細の分離 |


大まかなキーワードは以下のようなものがあります。

- GOF (Gang of four)
- MVC
- Clean Architecture
- DI (Dependency Injection)

## オブジェクト指向の指標

オブジェクト指向は原理原則の類なので、
その実現方法には実装する人ごとの違いが出来てしまします。

また、プログラミングをするときに常に余裕があるとも限らず、
つい乱暴な書き方をしてしまうこともあるでしょう。

そうしたプロジェクトを助けてくれるのが、
コードの品質を計測する「指標」です。

指標はあくまでものさしであり、
開発の目的にはなりませんが、
「仕事の価値の裏付け」や「チームの成熟度」など、
様々な場面で使える道具となります。

この指標について、心の片隅に置いておいてください。

大まかなキーワードは以下のようなものがあります。

- 凝集度
- 結合度
- 循環的複雑度
- 継承の深さ

## 参考

オブジェクト指向の勉強で初心者向けの日本語ページを集めてみました。
今回の僕の記事が、こうした知識をかみ砕く力になること願っています。

なお、こちらは完全に独断と偏見で選んでいるため、
「俺のベストはこれだ！」があればコメントでリンクをください。

- 新人プログラマに知っておいてもらいたい人類がオブジェクト指向を手に入れるまでの軌跡
    - https://qiita.com/hirokidaichi/items/591ad96ab12938878fe1
- オブジェクト指向と10年戦ってわかったこと
    - https://qiita.com/tutinoco/items/6952b01e5fc38914ec4e
- オブジェクト指向の法則集
    - https://qiita.com/kenjihiranabe/items/9eddc70e279861992274
- 初心者プログラマが犯しがちな過ち25選
    - https://qiita.com/rana_kualu/items/379eefb3a40c6b44cb92
- 「オブジェクト指向プログラミング」と「関数型プログラミング」のたった一つのシンプルな違い
    - https://qiita.com/hirokidaichi/items/efeee20917ee2b478ec9
FreeBSDな人がDebianを使う

ずっと、FreeBSD使ってきたけど、なにかとFreeBSDで動かないものとか多くていまいちなので、
FreeBSD使ってきた人がDebian使い始めるmemo

と、言っても事の発端はAnsibleでZABBIX4構築するためなので、初期設定もAnsible使ってみました。

## Ansibleの導入

標準だとAnsibleのバージョンが古いため、Ubuntu PPAで配布されているものを利用します。
(参照：https://docs.ansible.com/ansible/2.5/installation_guide/intro_installation.html#latest-releases-via-apt-debian)

```/etc/apt/sources.list
deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main
```

```
# apt update
# apt install dirmngr
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 93C4A3FD7BB9C367
# apt install ansible
```

## Playbookの作成

AnsibleのPlaybookを作ります。

```setup.yml
---
- hosts: localhost
  user: root
  vars:
    admin_name: USER
    admin_password: PASSWORD
    admin_public_key_path: ~/.ssh/id_rsa.pub
  tasks:
    - name: set timezone to Asia/Tokyo
      timezone:
        name: Asia/Tokyo

    - name: Install sudo
      apt:
        name: sudo

    - name: Install ufw
      apt:
        name: ufw

    - name: Deny everything and enable UFW
      ufw:
        state: enabled
        policy: deny

    - name: Set logging
      ufw:
        logging: on

    - name: Accept SSHd
      ufw:
        rule: limit
        port: ssh
        proto: tcp

    - name: disallow root SSH access
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: "^PermitRootLogin "
        insertafter: "^#PermitRootLogin"
        line: "PermitRootLogin no"
        state: present

    - name: disallow password authentication
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: "^PasswordAuthentication "
        insertafter: "^#PasswordAuthentication "
        line: "PasswordAuthentication no"
        state: present

    - name: Add a new user
      user: name={{admin_name}} password={{ admin_password }} state=present group=sudo

    - name: resister a public key
      authorized_key:
        user={{ admin_name }}
        key="{{ lookup('file', '/root/.ssh/authorized_keys') }}"

    - name: restart sshd
      service: name=sshd state=restarted
```

## Playbookの適用

localhostの後のカンマがミソらしい

```
#  ansible-playbook -i localhost, -c local setup.yml
```

## 細かいところ

そのうち、Ansibleにまとめます。

### コマンド履歴の前方一致

FreeBSDだと、過去に入力したコマンドの一部を入力し、上カーソルを押すと、
前方一致で履歴表示するけど、Debianはそうもいかない。

ホームディレクトリの.inputrcに次の設定を入れると同じようになる。

~~~ ~/.inputrc
"\e[A":history-search-backward
"\e[B":history-search-forward
~~~

### ll が使えるようにする

~~~ ~/.bash_profile
alias ll='ls -l --color=auto'
~~~

### 外にメールを投げられるようにする

FreeBSDだとSendmailが入ってて、SmartHostを設定すれば、sendmailコマンドから
メールが投げられるけど、Debianだとそういうの無いみたいで、ssmtpを使うといいっぽい

~~~
# apt get install ssmtp
~~~

手元の環境では、認証必要ないSMTPサーバがいるのでこんな感じ

~~~/etc/ssmtp/ssmtp.conf
mailhub=RelayHost:25
hostname=ThisHostName
~~~~
pythonで画像の拡張子変換

pythonを用いて画像処理を行う機会があったのですが，拡張子がバラバラで，使いたいライブラリに対応していない（特に.pdf）経験があり，わかりやすく変換できるものがあればなぁと思い，作ってみました．
スクリプト諸々はGithubにあげていますが，諸々不慣れですので，アドバイスいただけると幸いですm(_ _)m


## 実行環境
ubuntu 16.04
python 3.6.0

また，pythonモジュールとして
- Pillow(PIL)
- OpenCV
- pdf2image (https://github.com/Belval/pdf2image) 
が必要になります．

## ダウンロード
githubからとってくる．

```bash
git clone https://github.com/HisayaMiyao/image2image
```


## 実行方法
```bash
python image2image.py {対象画像が入ったディレクトリのパス} {変換前拡張子} {変換後拡張子}

#例
python image2image.py images_jpg .jpg .png
```

##対応拡張子
.bmp .dib .eps .gif .hdr .ico .im .jp2 .jpe .jpeg .jpg .pbm .pcx .pdf .pgm .pic .png .pnm .ppm .pxm .ras .sgi .sr .tif .tiff .webp
SQLでNULLとの比較結果をTRUE/FALSEにしたいときはIS DISTINCT FROM演算子を使う

一般的にSQLではNULLとの比較に通常の値比較`=`ではなく`IS NULL`を使います。`=`でnullと値を比較してしまうとUNKNOWNとなる処理系が多いためです。

そこで

- 値とnullの比較はfalseに
- nullとnullの比較はtrueに

という比較がしたい時があるかもしれません。そんな時には`IS DISTINCT FROM`もしくは`IS NOT DISTINCT FROM`という比較演算子が使えます。

| A | B | A = B | A IS NOT DISTINCT FROM B |
|:--|:--|:--|:--|
| 0 | 0 | true | true |
| 0 | 1 | false | false |
| 0 | null | unknown | false |
| null | null | unknown | true |

# 検証環境

```
postgres=# SELECT version();
                                                             version                                                              
----------------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 10.1 on x86_64-apple-darwin13.4.0, compiled by Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn), 64-bit
(1 row)

```

```
$ sqlite3 --version
3.22.0 2018-01-22 18:45:57 0c55d179733b46d8d0ba4d88e01a25e10677046ee3da1d5b1581e86726f2171d

```

# PostgreSQLでの例

```sql
--nullと値の比較(結果はunknown)
postgres=# select null = 4;
 ?column? 
----------
 
(1 row)

--値と値の比較(結果はtrue/false)
postgres=# select 4 = 4;
 ?column? 
----------
 t
(1 row)

--is distinct fromを使った比較(結果はtrue/false)
postgres=# select null is distinct from  4;
 ?column? 
----------
 t
(1 row)

-- 同等かどうかを調べるときは is not distinctを使う
postgres=# select null is not distinct from  4;
 ?column? 
----------
 f
(1 row)

-- is distinct fromでは値同士も比較できます
postgres=# select 4 is distinct from  4;
 ?column? 
----------
 f
(1 row)


```


# sqliteではIS DISTINCT FROMの代わりにISを使う

sqliteでは`IS DISTINCT FROM`が使えません。代わりに`IS`で比較を行うことができます

```
sqlite> select 4 = 4;
1
sqlite> select 4 is null;
0
sqlite> select 4 is 4;
1
sqlite> select 4 is 5;
0
sqlite> select null is null;
1
```

# 他

MySQLでは`IS DISTINCT FROM`風の比較に<=>が使えます

# 備考

2018年現在対応しているベンダーは少ないですが、標準SQLのため今後他のベンダーのRDBMSでも利用できるようになる可能性が大いにあります

# 参考

- https://modern-sql.com/feature/is-distinct-from
- プログラマのためのSQL 16. 3 IS [NOT] DISTINCT FROM 演算子
pythonスクリプトをexeに変換する（つまづきポイントまとめ）

# はじめに

pythonスクリプトをExeファイルに変換しようとした時に、いくつか、つまずいた点があったので、解決策を共有します。

OSは、Windows10
Pythonは、Anacondaでインストールした 3.6.4です。

# pythonスクリプトをExeファイルに変換する意味

pythonスクリプトをExeファイルに変換することには、
以下の意味があります。

 * pythonをインストールしていないPCでも実行できるようになる
 * pythonスクリプトの中身を隠すことができる

# 一般的に紹介されている方法

py2exeを利用するか、pyinstallerを利用するかの選択肢があります。
基本的にどちらも若干面倒ですが、今回はpyinstallerを利用する方法を紹介します。

### ①pipで、pyinstallerをインストールする
```
$ pip install pyinstaller
```

簡単にインストールできます。

### ②pyinstallerでpythonスクリプトをexeファイルにする

```
$ pyinstaller ○○.py --onefile
``` 

一つのexeファイルにまとめるために「--onefile」をオプションで指定します。
本当であれば、これで終了!
なのですが、pythonスクリプトをexe化する場合、大体色々怒られるので、ここからが勝負です。
以降で、私がつまずいた点を共有したいと思います。

# exeに変換する上でつまずくポイント

### その１「AttributeError: 'str' object has no attribute 'items'」

![エラー1.PNG](https://qiita-image-store.s3.amazonaws.com/0/254780/5b2fa77b-b62e-1213-347e-39cfc6bfce97.png)

1回目落ちました。
この問題を解決するためには、setuptoolsの更新が必要です。
参考：[Pyinstaller compile to exe](https://stackoverflow.com/questions/35613300/pyinstaller-compile-to-exe)

```
# 解決策１
$ pip install --upgrade setuptools
``` 

これにより、AttributeErrorでは落ちなくなります。

### その２「Cannot find existing PyQt5 plugin directories」

![エラー3.PNG](https://qiita-image-store.s3.amazonaws.com/0/254780/64c9e9ba-f328-a818-3a02-595b7a6898f1.png)


2回目落ちました。
この問題を解決するためには、PyQt5をインストールする必要があります。
参考：[Exception: Cannot find PyQt5 plugin directories when using Pyinstaller despite PyQt5 not even being used](https://stackoverflow.com/questions/39736000/exception-cannot-find-pyqt5-plugin-directories-when-using-pyinstaller-despite-p)

```
# 解決策２
$ pip install PyQt5
``` 

これにより、PyQt5が見つからないという理由では落ちなくなります。

### その３「UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 130: invalid start byte」

![エラー5.PNG](https://qiita-image-store.s3.amazonaws.com/0/254780/b8c50675-0eda-4784-49c2-7a10b916a440.png)



3回目落ちました。
python2系で頻出の、UnicodeDecodeErrorです。（環境は3.6.4ですが）
この問題を解決するためには、compat.pyを書き換える必要があります。
（もっと良い解決策ないのかな。。）

参考：[Error when using pyinstaller: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff](https://stackoverflow.com/questions/47692960/error-when-using-pyinstaller-unicodedecodeerror-utf-8-codec-cant-decode-byt)

```
# 解決策３
# この場合は、370行目を書き換え
# out = out.decode(encoding)
out = out.decode(encoding, errors='ignore')
``` 

エラーをignoreします（強引）。
これにより、UnicodeDecodeErrorで落ちなくなります。

そして、これで無事動くようになりました！

``` 
548794 INFO: Building EXE from EXE-00.toc completed successfully.  # 正常完了
``` 

# 最後に
些細な事で、つまずくケースは結構多いと思います。（この記事書くためのデバックで2時間かかった。。）
今回の解決策は一例ですが、pythonスクリプトをexeファイルする際の参考にして頂けると嬉しいです。

# 参考
[PythonスクリプトをWindows環境で動くexeファイルにしよう！](https://www.sejuku.net/blog/65881)
[Pyinstaller compile to exe](https://stackoverflow.com/questions/35613300/pyinstaller-compile-to-exe)
[Exception: Cannot find PyQt5 plugin directories when using Pyinstaller despite PyQt5 not even being used](https://stackoverflow.com/questions/39736000/exception-cannot-find-pyqt5-plugin-directories-when-using-pyinstaller-despite-p)
[Error when using pyinstaller: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff](https://stackoverflow.com/questions/47692960/error-when-using-pyinstaller-unicodedecodeerror-utf-8-codec-cant-decode-byt)
Rails コールバックについて　その1

曖昧な理解だったコールバックについてまとめた。

## コールバックとは？
オブジェクトのライフサイクル期間の特定のタイミングで呼び出されるメソッド

## 実際に使ってみた
決まったタイミングで必ず呼びたいメソッドは、コールバックを使用すると良さそう

下記は、postインスタンスが作られる時に、必ずurl_tokenカラムにランダムな文字列を入れる実装
`before_create` を使用しているので、createアクションが呼ばれる前に必ず呼ばれる

```ruby:post.rb
class Post < ApplicationRecord
  belongs_to :user
  # create時に必ず呼ばれる処理
  before_create :set_rand_id

  private
　　 # postsテーブルのurl_tokenカラムにランダムな１６桁の数字（文字列）を入れる処理
  def set_rand_id
    self.url_token = 16.times.map{rand(0..9)}.join()
  end
end
```
## コールバックの種類

 objectの作成/更新
- before_validation
- after_validation
- before_save
- around_save
- before_create(update)
- around_create(update)
- after_create(update)
- after_save

`after_save` は作成と更新の両方で呼び出されるが、コールバックマクロの呼び出し順にかかわらず、必ず、より具体的な `after_create` および `after_update`よりも後に呼び出される。


objectの削除
- before_destroy
- around_destroy
- after_destroy

## after_initialize と after_find
`after_initialize` => Active Record オブジェクトが1つインスタンス化されるたびに呼び出される
※インスタンス化は `new`　以外にもDBからレコードを読み込んだ時も実行される

`after_find` => Active Record がデータベースからレコードを１つ呼び込むたびに呼び出される

どちらも定義されている場合は、 `after_find` が先に呼ばれる

```ruby:post.rb
class Post < ApplicationRecord
  belongs_to :user
  after_initialize do |post|
    puts "オブジェクトは初期化されました"
  end

  after_find do |user|
    puts "オブジェクトが見つかりました"
  end

>> Post.new
"オブジェクトは初期化されました"
=> #<User id: nil>

>> User.first
オブジェクトが見つかりました
オブジェクトは初期化されました
=> #<User id: 1>

```
続きはその２で
Jenkinsのエラー対応

# Jenkinsの管理画面で発生したエラーの対応

## ディスク容量エラー

いつもどおりJenkinsの画面を開くと、以下のエラーが表示されていました
「java.io.IOException: No space left on device」

ログインボタンも表示していなかったので、jenkins構築環境にログインして原因を調べました。

- 調べた結果以下の2通りで発生することが判明
 - ディスク容量不足
 - inode不足

とりあえず、ディスク使用量を確認

```
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
~
/dev/sda1        30G   30G  2.3M 100% /
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/sdb1       7.8G   18M  7.4G   1% /mnt
tmpfs           395M     0  395M   0% /run/user/1000
```
ビンゴです。100%になってました。

Jenkinsのルートディレクトリへ移動してディレクトリごとの容量を確認

```
$ cd /var/lib/jenkins
$ du -sh ./*
~
5.0G	./workspace
```
workspaceで多く利用してました。
原因はジョブでGitを利用したことによる対応で、すごく大きな容量のリポジトリをcloneしていたために急激に容量不足となってしまいました。

念の為、inodeも確認

```
$ df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
~
/dev/sda1      3840000 566748 3273252   15% /
tmpfs           505072      1  505071    1% /dev/shm
tmpfs           505072      3  505069    1% /run/lock
tmpfs           505072     17  505055    1% /sys/fs/cgroup
/dev/sdb1       524288     12  524276    1% /mnt
tmpfs           505072      4  505068    1% /run/user/1000
```
こちらは使用率15%なので問題ありませんでした。
ビルド結果を削除しないと、ログがたまっていってしまいinode不足により同様のエラーが発生することがあるみたいなので、ジョブの設定でビルドの保持期間はきちんと設定しておきましょう。


不要なファイルやディレクトリを削除して、Jenkinsを再起動したら問題なく動きました。
その際にブラウザからの再起動ではエラー画面が解決しませんでした。

```
http://domain:port/safeRestart
```

なので、コマンドから再起動で通常の画面が表示されました。

```
$ sudo /etc/init.d/jenkins restart
```



# タイムアウトエラー
ジョブを実行していると、コンソール画面が以下の表示となりエラーとなってしまいました。

```
ERROR: Timeout after 10 minutes
ERROR: Error cloning remote repo 'origin'
hudson.plugins.git.GitException: Command "git fetch --tags --progress giturl +refs/heads/*:refs/remotes/origin/*" returned status code 128:
stdout: 
```

Gitのプラグイン実行時に10分のタイムアウトエラーのような表示。
jenkinsの環境のワークスペースを確認してみました。

```
$ ls -a /var/lib/jenkins/workspace/ジョブ名
.git
```
.gitだけありました。
Gitのリポジトリが大きくて、cloneで10分以上立ってしまっていた可能性がったので、
対象のリポジトリをworkspaceにcloneしました

```
$ cd /var/lib/jenkins/workspace/ジョブ名
$ git clone giturl .
```
jenkins上でもタイムアウトの設定を10分から変更できるみたいです。

cloneが完了後は問題なくジョブが実行できました。
Linuxでmailを連続的に送るシェルスクリプト

# 対応
echoで本文作成
パイプで本文をmailコマンドに連携する
-sで件名、-Sでsmtpサーバ、-rで送信アドレス、最後の引数に宛先アドレス

```
for i in `seq 3`
 for y in `seq 100`
 do
  echo "test ${i} ${y}" mail | mail -s test -S smtp=XX.XX.XX.XX:25 -r xxx@co.jp xxx@co.jp
  sleep 2s
 done
done
```
[Git]FORKしたリポジトリを最新にする方法

FORKしたけど最新にする方法をうっかり忘れてしまった時の備忘録
※developをプッシュする運用の場合

・upstream
FORKしたリポジトリとは別に取得用にupstreamというリポジトリを作成
タグを全て含めフェッチする。
・originへ反映
FORKしたoriginのdevelopをチェックアウトする
upstreamのdevelopを右クリックし、「現在のブランチにupstream/developをプル」を選択する
origin/developをプッシュする
SIGSEGVをハンドリングした時のsi_addrは時として信用できない

まずは以下のCプログラムを実行してみましょう。

```c
#include <stdio.h>
#include <string.h>

int main() {
    void* ptr = (void *)(1UL<<48);
    fprintf(stderr, "ptr=%p\n", ptr);
    memset(ptr, 'a', 1);
    return 0;
}
```

もちろん、以下のようにSEGVで落ちることでしょう。

```
ptr=0x800000000000
Segmentation fault
```

さて、このプログラムに対して`sigaction()`システムコールを使ってSIGSEGVをハンドリングするコードを書き加えてみます。
ハンドリングの具体的な方法については割愛します。

```c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void sigac(int signo, siginfo_t *siginfo, void *ptr) {
    fprintf(stderr, "si_addr=%p\n", siginfo->si_addr);
    exit(1);
}

int main() {
    void* ptr = (void *)(1UL<<47);
    struct sigaction act;
    act.sa_handler = SIG_DFL;
    act.sa_sigaction = sigac;
    act.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
    sigprocmask(SIG_BLOCK, NULL, &act.sa_mask);
    sigaction(SIGSEGV, &act, NULL);

    fprintf(stderr, "ptr=%p\n", ptr);
    memset(ptr, 'a', 1);
    return 0;
}
```

このコードを実行した時に、多くの人は以下の出力を期待するでしょう。

```
ptr=0x800000000000
si_addr=0x800000000000
```

しかし現行(2018年10月現在)のほとんど(全て？)のIntel製64ビットCPUでは以下のような出力になると思われます。

```
ptr=0x800000000000
si_addr=(nil)
```

`(nil)`ということは、`siginfo->si_addr`には`0x800000000000`ではなく`0x0`が代入されているということです。

```c
void* ptr = (void *)(1UL<<47);
```

この挙動のヒントはここにあります。ここでピンときた人はおそらく正解までたどり着いているでしょう。
この値を1つ小さくしてみましょう。つまり、当該部分のコードを以下のように変更します。

```c
void* ptr = (void *)((1UL<<47)-1);
```

このようにすると当初の想定通り、

```
ptr=0x7fffffffffff
si_addr=0x7fffffffffff
```

と出力されます。

これらの事象の原因は現行のIntel製64ビットCPUでサポートされている仮想メモリ空間が64ビットでなく48ビットであることにあります。
48ビットを超える範囲の仮想メモリアドレスで何かをやろうとすると、範囲外アクセスによってSEGVが発生します。しかし、これをハンドリングしようとするとヌルポインタ操作を行った場合と同様の挙動を示してしまうようです。
(この挙動についてIntel側のマニュアル等に書いてあったらどなたか教えてください……)
しかしながらC言語上では何も問題がないため、メイン関数内の方の`fprintf`は普通に出力してくれます。

ちなみに、

```c
void* ptr = (void *)((1UL<<47)+1);
```

とすると

```
ptr=0x800000000001
si_addr=(nil)
```

のようになります。せめて`0x1`になって欲しいところではありますが。

ちなみにARM64をはじめとする、他の64ビットプロセッサの多くも仮想メモリ空間が48ビットらしいのですが、手元にARM64環境がないので検証できず。

結論としては *`si_addr`が`0`であっても、アクセスしようとしていた仮想メモリアドレスが`0x0`であるとは限らない* ということです。
もし理解不能なヌルポインタ系のエラーで引っかかったら、`si_addr`の値を調べる以外の方法で、アクセスしようとしていた仮想メモリアドレスが`0x800000000000`以上でないかを確認しましょう。
AWS CloudTrail

##1.AWS CloudTrailとは？##
「いつ誰が何をしたのか」を記録しておいてくれるサービスです。

##2.特徴##

- デフォルトでOnになっている。
- 90日間保存できる。（90日以上保存させる場合は、S3に保存させるようにする。）
- S3の保存先はS3でバージョンニングを有効にするか、クロスアカウントなどを利用することを検討する。
- 5分おきに作成される。

##3.イベント履歴##
「イベント履歴」をクリックしてみましょう。
CloudTrail はデフォルトで有効になっているため、今まで行ってきた「サインイン」や「IAM ユーザーの作成」などもすべてイベントとして記録されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/6b67c73b-c196-eaad-70e9-e0ca05040d13.png)

このようにCloudTrail では何も設定しなくても、デフォルトで過去90日間のイベントが無料で記録されています。
今後もし「消した覚えがないのにサーバが跡形もなく消え去っている！」というようなことがあったら、先ずCloudTrail を開いていつ誰がサーバを削除したのか確認してみましょう。

##4.証跡情報##

- [管理イベント](https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/logging-management-and-data-events-with-cloudtrail.html#logging-management-events):EC2インスタンスやS3バケットの作成
- [データイベント](https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/logging-management-and-data-events-with-cloudtrail.html#logging-data-events):S3バケットのデータ操作、Lambda関数の実行など

＊管理イベントのみデフォルトで有効になっています。

画面だけ確認して見ましょう。

「認跡の作成」
![スクリーンショット 2019-01-31 21.18.44.png](https://qiita-image-store.s3.amazonaws.com/0/280929/0dc778e2-1427-29dc-aa24-04136741c94f.png)

証跡名：適当な名前
証跡情報を全てのリージョンに適用：すべてのリージョンに残すか選択します。
![スクリーンショット 2019-01-31 21.26.29.png](https://qiita-image-store.s3.amazonaws.com/0/280929/5e1ea38b-30cf-6613-8613-df5741402e3b.png)

管理イベント 
読み込み/書き込みイベント：すべて・読み取り専用・書き込み専用・なし から選択できます。
![スクリーンショット 2019-01-31 21.26.38.png](https://qiita-image-store.s3.amazonaws.com/0/280929/deb618a1-498b-8504-6cfa-1644263f9bce.png)

データイベント
S3・Lambdaを選択できます。
![スクリーンショット 2019-01-31 21.34.45.png](https://qiita-image-store.s3.amazonaws.com/0/280929/45277566-1e51-3e3a-3813-60180792092c.png)

ここで新しいS3バケットを作成して保存することもできます。
![スクリーンショット 2019-01-31 21.35.57.png](https://qiita-image-store.s3.amazonaws.com/0/280929/41950651-a9c9-3e49-d6ad-278b736c0001.png)

なお、追加料金が発生するため、作成しませんでした。


##5.暗号化##

- デフォルトでCloudTrailイベントログファイルは、Amazon S3サーバーサイド暗号化（SSE）を使用して暗号化されています。 
- ログファイルをAWS KMSキーで暗号化することもできます。


#6.CloudTrail Insights#

- Insights は異常なアクティビティがログに記録された場合、Insights イベントがこのテーブルに 90 日間表示されます。
- CloudTrail Insights を有効にした場合は、最初の Insights イベントを受信するまでに最大 36 時間かかります。


#7.ログファイルの整合性の検証#

- CloudTrail が配信した後でログファイルが変更、削除、または変更されなかったかどうかを判断する。
- 仕組みとしては１時間毎にハッシュ値を取得して、それを照合している。

https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html
DoctrineのDQL関数拡張を行う方法

# DoctrineのDQLに存在しない関数をユーザー独自関数として拡張を行う方法のメモ

MySQL独自関数やPostgreSQL独自関数をDQLで呼ぼうとすると、

>Doctrine\ORM\Query\ QueryException
>[Syntax Error] line 0, col 42: Error: Expected known function, got 'DATEDIFF'

のようなエラーが出る。
これはDQLに該当の関数が実装されていないからで、ユーザー独自関数としてDQLに登録すれば使えるようになる。その方法の覚書。

##Doctrineに拡張できるSQL関数リスト
[DoctrineExtensions](https://github.com/beberlei/DoctrineExtensions)

---
##DQLへの関数拡張を扱った記事リスト
[Add MySQL function DATE_FORMAT to Symfony Doctrine DQL](https://medium.com/@narven/add-mysql-function-date-format-to-symfony-doctrine-dql-288ac51941c2)

[DQL User Defined Functions](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/cookbook/dql-user-defined-functions.html)

[Symfony2【Doctrine DQL関数拡張】MySQL(PostGreSQL)のNOW,ROUND,FLOOR,GROUP_CONCAT等の関数を使用（EC-CUBE3）](https://webcode-lab.com/topics/blogid/24/)

[DoctrineでSQLの日付関数を使う方法](https://tech.quartetcom.co.jp/2015/12/01/doctrine-date-function-extension/)

[How to Register custom DQL Functions](https://symfony.com/doc/current/doctrine/custom_dql_functions.html)

---
Symfony2の場合、config.yml に記載して登録する方法もある
[In Symfony2 you can register functions in config.yml](https://github.com/oroinc/doctrine-extensions/#symfony2)

---
##EC-CUBE4系でハマったところ
EC-CUBE4系では、下記のリンク先のように

> \$emConfig = \$this->getEntityManager()->getConfiguration();
> \$emConfig->addCustomDatetimeFunction('YEAR', 'DoctrineExtensions\Query\Mysql\Year');
> \$emConfig->addCustomDatetimeFunction('MONTH', 'DoctrineExtensions\Query\Mysql\Month');
> \$emConfig->addCustomDatetimeFunction('DAY', 'DoctrineExtensions\Query\Mysql\Day');

の方法で\$configを設定しないとユーザー独自関数の登録が上手くいかなかった。
[How To Select YEAR() MONTH() DAY() In Doctrine2](https://simukti.net/blog/2012/04/05/how-to-select-year-month-day-in-doctrine2/)
Xcode10 + Swift 4.2 + SnapKit 4.2.0

Xcode10でSnapKitをcocoapodsでインストールすると、SnapKitのバージョン4.0.0がインストールされて、Xcodeで``Error: 'NSLayoutAttribute' has been renamed to 'NSLayoutConstraint.Attribute``などのエラーが出でます。

SnapKitの公式Githubでも``Issues``が上がっており、探ってみるとgit``tag``の``4.2.0``で解決できるそうなので、``Podfile``で``SnapKit``のインストールに``git``と``tag``を指定してインストールすることで解決できたので備忘録

```shell:Podfile
# Uncomment the next line to define a global platform for your project
platform :ios, '12.0'

target 'MyApp' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for MyApp
  pod 'SnapKit', :git => 'https://github.com/SnapKit/SnapKit.git', :tag => '4.2.0'

end
```
Macの高速化と最適化

## マシンが遅くなる原因
メモリ不足

## メモリ空き容量の確認

`アプリケーション > ユーティリティ > アクティビティモニタ > メモリ`

## ディスク空き容量の確認

`リンゴマーク > このMacについて > ストレージ`

## 参考
### メンテナンス
- [【決定版】MacOS X 高速化テクニック](https://qiita.com/soushiy/items/b56d4961d54972bc4b9e)
- [Macの負担を軽くする設定&高速化メンテナンス13選 \| D-Box](https://do-zan.com/mac-maintenance/)
- [【保存版】Macが重い&遅い！そんな時の対処法と解決方法をここに記します！高速化で快適に！ - アドエフ！ブログ](http://www.ad-ftbdiary.com/entry/2017/05/16/192447)
- [起動の遅いMacを高速化する方法10選 \| Crucial Japan](http://www.crucial.jp/jpn/ja/learn-with-crucial/mac-users/how-to-speed-up-your-mac-system)

### メモリ解放
- [Macのメモリ解放を行う方法を解説！メモリ不足を解消しよう！ \| Aprico](https://aprico-media.com/posts/1195)
- [Macでメモリ解放を行う１番良い方法はアプリか再起動か「sudo purge」コマンドのどれ？ \| レビューログ](https://reviewlog.info/mac-memory-clean/)
- [Mac のメモリ解放無料アプリ「Memory Cleaner」 \| Macガレージ](https://satoshisgarage.tech/?p=7356)
- [Mac初心者に送るMacのメモリ管理について](https://qiita.com/zakiyamaaaaa/items/20d4dc4a3d587500e1f1)
draw.io > Google Drive: Realtime API廃止 (2018-11-18)後 > 使えるようだ

### 関連

- [Google Drive > 3rd パーティへのRealtime API capabilities の停止 (2018-12-11)](https://qiita.com/7of9/items/a328fd0f331f9f1feaa2)
- [@MindMup2 > Collaborative maps will stop working in December 2018 > Google Drive integrationの変更(2018-12-11)に関係](https://qiita.com/7of9/items/1e1b1d75dcde07ae5d7a)

### Google Drive > Realtime API廃止 (2018-11-18)後のdraw.io

MindMupにおいてはGoogle DriveのRealtime API廃止後に問題があるとのことで、MindMup Cloudへの利用に切替えた。

一方で、draw.ioはどうなるのか?

問い合わせたところ、下記のような回答を得た。

> 「GoogleのRT systemへの置換えプロトコルがあるため、そのまま使えるよ」

問題なさそうだ。

(MindMupで移行が必要なのは良く分からない)
遠方の人と一緒にリアルタイムで開発してみた話

# 前置き
私には凄い知識を持っているプログラマーのような記事は書けないので、これはあくまでもこんなことがあったなぁという経験談および思い出話である。また、技術ネタを書かないと削除されるという噂を聞いたため、できる限り技術と絡む話になるように**頑張ります**。
また、開発といっても、でっかいものではないです。

# 物語
あるところに言語（**語学**の方）オタクな人がいました。
その人は、いきなり思いました。「なんか面白いことないかな〜」
すると運が良いことに、面白い人を見つけました。

### 面白い人のプロフィール（詳細は全くもって省く）
- Developer
- English teacher
- Live in USA
- Born in USA

そこで~~あざとい~~私は思った。「こんな一石二鳥なことってあります？」
私は、プログラミングのレッスンというべきか英語のレッスンというべきか（**英語の文法云々ではなくコミュニケーションスキル向上が目的**）...というものを受けることに決めたのだが、じゃあ一緒に小さなプロジェクトでもやってみましょうかという話になった。

# どんな風に進めたか
## 使ったコミュニケーションツール
SkypeかZoomかという話になったけど、慣れているSkypeの方を選んだ。
（でも、Zoomを好む人が最近増えつつある気はしている）

## リアルタイムで共同作業
最初は、Skypeで画面共有しながら進めるのかしらと思っていたのだが、
まさに、遠隔で共同作業するのに最適なサービスというのがこの世には存在しており、
それが[Glitch](https://glitch.com)な訳です。（ので、Skypeは音声としての役割）
Glitchの使い方は[こちら](https://glitch.com/help/how-can-i-get-help-with-code-in-my-project/)にありますが、要するに

- リアルタイムで
- 誰とでも
- プロジェクトを立てれて
- そのプロジェクトを公開することもできる

~~（↑これ、リストにする必要あった？）~~
画面はこんな感じ
（この時は、SinatraとFlickr APIを使って、Flickrの画像をランダムに表示するってのをやりました）
<img width="1439" alt="index_html_–_simple-project.png" src="https://qiita-image-store.s3.amazonaws.com/0/287149/8b164497-6a46-f7d3-6649-b4338d0cb355.png">
* SinatraやFlickr APIの詳しいお話は、どこかの誰かがしてくれていると思うので、ここでは省きます。

# 感想
- リアルに人と「ここはこうしたほうがいいんじゃないああしたほうがいいんじゃない」と話をしながら（**チャットではなく実際に話すってのがイイ**）、かつ、ソースコードが変更されるのも**リアルタイムに見る・触る**ことができたことが、今までになく斬新な経験となった。
- やっぱこういうとこで使う英語はちょっと違うのかしらと身構えていたが、そんなことはなく、普段からの会話に問題がなければ全然問題ないです。まぁ、むしろ、**単語だけ知っていても相手とコミュニケーションしようという意思がなければ何にもならない**ってことです。
- こんなツールもあるのか、という新たな発見ができた。

# おまけ
- backend開発に役立つよ -> [https://repl.it](https://repl.it)
- Sinatraの基礎の基礎はこれで勉強した -> [https://www.udacity.com](https://www.udacity.com)
WindowsMR+ViveTracker

# WindowsMRでViveTrackerを使いたい
現在Windows10ではWindowsMRがSteamVRとして動作するようになっています。
WindowsMR for SteamVRを起動するとSteamVRのダイアログが起動しWindowsMRのHMDを認識すると
![SteamVR ステータス 2018-10-23 14.12.44.png](https://qiita-image-store.s3.amazonaws.com/0/128561/74a80aa0-e4e0-00d3-80a9-28d8bcc7ec0f.png)
こんな感じでWindowsMRがSteamVR上で動くようになります。
Unityで開発する場合SteamVR SDKを入れて普通にSteamVRとして開発出来るようになります。

以前、[UnityでViveやWindowsMRのモーションコントローラーの入力を統合する方法](https://qiita.com/hadoumune/items/060849776c31ccb1bef3)
という記事を書きましたがInput周りを考えるとこちらの方が色々とスムーズに連携出来ます。

ここまで動いたらViveTrackerとかViveWand（Viveコントローラー）とか使えないかなとか思う人も中には居るでしょう。
特に6DoFが使えるまともで購入しやすいTrackerとなると今の所ViveTrackerぐらいしか選択肢がありません。

## Vive機器を認識させる
試しにベースステーションを設置してViveTrackerを繋いでWindowsMR for SteamVRを起動したのですが当然認識しませんでした。

[【Unity】ViveのHMDなしにTrackerを使う]
(http://shop-0761.hatenablog.com/entry/2018/01/08/034418)
[HMDなしのSteamVRトラッキング]
(http://help.triadsemi.com/steamvr-tracking/steamvr-tracking-without-an-hmd)

上記の記事ではSteamVRのベータ版を使うとありますが流石に仕事で使っている環境にSteamVRのベータ版を入れる気持ちは起きません。
今回はHMD無しという訳ではなく、WindowsMRを使うので少し事情が異なります。

どうにかならないかなと思ったらありました。
https://www.reddit.com/r/Vive/comments/86ri8w/vive_controllers_work_with_the_odyssey/

方法は凄く簡単で

```
C:\Program Files (x86)\Steam\config\steamvr.vrsettings
```
に以下の設定を追加するだけです。

```json:steamvr.vrsettings
   "steamvr" : {
      "activateMultipleDrivers" : true,
```
activateMultipleDriversをtrueにしてSteamVRとか諸々を再起動して下さい。
ViveTrackerのペアリングなどは先に済ませて置くことを推奨します。

ViveTrackerを起動したまま再起動すると
![SteamVR ステータス 2018-10-23 14.22.22.png](https://qiita-image-store.s3.amazonaws.com/0/128561/e75f07b1-5f05-7a6b-7709-55b689e8636b.png)

以下の様にベースステーションと共にViveTrackerが認識されるようになります。
まだUnity上では確認していませんが多分普通に動作するでしょう。多分。

実際に確認してみた所Trackerが無事表示されましたが、カメラの位置が3mとかになります。Trackerの位置が1.9mとかになっているので、どうもベースステーションからの位置とWinMRで認識している世界の位置が合ってない感じがしてます。
Linuxサーバ上の日次ログファイルを圧縮してS3の年月ディレクトリにアップロードする

# 前提

- [aws cliがインストール](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/installing.html)されていること
- バックアップ先S3に書き込み権限を持つIAMユーザのプロファイルが実行端末に設定されていること($ aws configure --profile プロファイル名)
- ログファイルはローテーションされていてファイル名にタイムスタンプが付与されていること。（本スクリプトはファイル名にタイムスタンプを付与しません）

# 環境

- Amazon Linux AMI release 2018.03
- aws-cli/1.15.83 
- Python/2.7.14 
- Linux/4.14.42-52.37.amzn1.x86_64 
- botocore/1.10.82

# 実行結果

スクリプト内定義で指定したファイルが圧縮されてバックアップ先Ｓ３のバックアップ先ルートの年/月フォルダの下に格納されます。
（例. mybucket/backup/logs/2018/10/application.2018-10-10.zip)

元のファイルは所定日数（KEEP_DAYSで指定）を経過すると削除します。

※月をまたぐ時に前月分が当月にまざります。

# bashスクリプト

```bash
#!/bin/bash
set -Ceu

export AWS_PROFILE=＜プロファイル名＞

AWS_CLI=/usr/bin/aws   # $ which aws  の実行結果を設定

TARGET_DIR=＜バックアップ対象ログファイルが格納されているディレクトリのフルパス＞
TARGET_FILE='application.20*.log'  # ファイル名（正規表現）

# 元ファイル（および圧縮ファイル）の保持期間
KEEP_DAYS=2

# バックアップ先（年月はスクリプトで付与するので含めない）
S3_BACKUP_ROOT_DIR=<バケット名>/path/to

# 圧縮
find $TARGET_DIR -name $TARGET_FILE -type f -exec zip -r {}.zip {} \;

# S3ディレクトリと同期する。圧縮前のファイル(拡張子log)は同期しない
DIR_YEAR=`date '+%Y'`
DIR_MONTH=`date '+%m'`
$AWS_CLI s3 sync ${TARGET_DIR} s3://$S3_BACKUP_ROOT_DIR/$DIR_YEAR/$DIR_MONTH/ --acl private --exclude '*.log'

# 古いファイルの削除
find ${TARGET_DIR} -mtime +$KEEP_DAYS -exec rm -f {} \;
```
C++ > unique_ptr > ポインタを取得する > .get() | EFFECTIVE C++ 68ページ目

```txt:動作環境
C++ Builder XE4
```

### .get()

unique_ptrで作成した後で、そのポインタを関数などで渡す時の書き方。

```cpp
std::unique_ptr<TStringList> fileList(new TStringList);
getFileList(fileList.get()); // 使用例
```

getFileList()の中で特定フォルダのファイルリストをfileListに格納する、など。

Note: 過去のある時期によく実装していた内容だが、その後、別の作業(Python, numpy, NetCDF, NCLなど）をしているうちに書き方を忘れました。。。備忘録として記事にします。

### 参考

- https://ja.cppreference.com/w/cpp/memory/unique_ptr/get

### 本(Kindle)の記載

@ EFFECTIVE C++: 55 Specific Ways to Improve Your Programs and Designs 
by Scott Meyers
68ページ目(/279ページ)

> tr1::shared_ptr and auto_ptr both offer a get member function to perform an explicit conversion, i.e., to return (a copy of)the raw pointer inside the smart pointer object:

```cpp
int days = daysHeld(pInv.get()); // find, passes the raw pointer
                                 // in pInv to daysHeld
```
Docker for windows で /var/run/docker.sock をマウントできるようにする

## 動作確認環境
以下のバージョンで確認しています。

```sh
Docker for windows : Docker 18.06.1-ce
```

## 背景
80番ポートを使うコンテナを複数起動したい時、もっとも簡単なソリューションがjwilderさんが公開されているリバースプロキシコンテナを使うことだと思います。

> nginxを使ったリバースプロキシ on Docker
https://qiita.com/ka2asd/items/372d30be64c57a8a81b1


これならnginxのconfigすら必要ありません。
httpだけではなくhttpsにも対応しています。所定の場所に証明書を配置するだけの圧倒的手軽さ。素晴らしい。

んが、Docker for Windowsで使用する場合、ちょっぴり問題があります。
``/var/run/docker.sock``をマウントする必要があるのですが、そこでエラーが出るのです。


**エラーメッセージ**

```sh
Cannot create container for service portainer: b'Mount denied:\nThe source path "\\\\var\\\\run\\\\docker.sock:/var/run/docker.sock"\nis not a valid Windows path'
```

こんな時はgoogle先生に助けてもらうのが一番です。

結果、githubにissueがたっているのを発見しました。

> docker-compose bind mount docker.sock not a valid Windows path
https://github.com/docker/for-win/issues/1829

長くスレッドが伸びているので要点だけ書きます。


## やること

docker-compose.ymlの並びに.envを作成する

```sh
- project_dir
  +--- docker-compose.yml
  +--- .env
```

.envの内容

```./.env
COMPOSE_CONVERT_WINDOWS_PATHS=1
```

以上!

元記事の下のほうに、stableじゃなくedge版のDocker for Windowsを使う必要があるとか書いてあって顔に縦線入ったのですが、試したみたところ現時点(2018/10/23)のstableの最新で問題なく動作しました。


では良いDockerライフを。
ASP.NET Web API でレスポンスの JSON を snake_case にする

# 前提

下のようなコントローラを作成したとします。

```SampleController.cs
namespace SampleProject.Controllers
{
    public class SampleController: ApiController
    {
        // GET api
        public List<User> Get()
        {
            return new List<User>()
            {
                new User() { FirstName = "Taro", LastName = "Suzuki" },
                new User() { FirstName = "Hanako", LastName = "Sato" }
            };
        }
    }
}
```

このとき Content-Type を application/json にすると JSON のレスポンスが得られるわけですが、フィールド名がデフォルトだと CamelCase になります。

```response.json
[
  {
    "FirstName": "Taro",
    "LastName": "Suzuki",
  },
  {
    "FirstName": "Hanako",
    "LastName": "Sato",
  }
]
```

# フィールド名を snake_case にする

route を定義しているファイル （通常 `App_Start/WebApiConfig.cs`） に設定を追加します。

```WebApiConfig.cs
using System.Web.Http;
using Newtonsoft.Json.Serialization;

namespace SampleProject
{
    public class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(/* route の定義 */);
            
            // これを追加
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver()
            {
                NamingStrategy = new SnakeCaseNamingStrategy()  // ここで NamingStrategy が見つからない場合は次節を参照
            };
        }
    }
}
```

# Newtonsoft.JSON をアップデートする

上のコード中にコメントしていますが、`NamingStrategy` プロパティや `SnakeCaseNamingStrategy` クラスが存在しないためエラーが出ていました。これは ASP.NET をセットアップしたときにバンドルされている `Newtonsoft.JSON` が古い（v6.0.4）のが原因なので、アップデートが必要です。

NuGet パッケージマネージャから `Newtonsoft.JSON` を検索し、アップデートしてください。[リリースノート](https://github.com/JamesNK/Newtonsoft.Json/releases/tag/9.0.1) によると、v9.0.1 で入った機能のようなので、それ以上にします。以下の説明では執筆時点（2018年10月23日）の最新版 v11.0.2 を使っています。

### MSB3247 警告が出る場合

アップデート後、ビルドすると以下の警告が出ました。

```
Microsoft.Common.CurrentVersion.targets(2052, 5): [MSB3247] 同じ依存アセンブリの異なるバージョン間で競合が見つかりました。Visual Studio では、この警告をダブルクリックする (または選択して Enter キーを押す) ことで、この競合を修正できます。または、アプリケーション構成ファイル内の "runtime" ノードに、次のバインド リダイレクトを追加します: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" /><bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" /></dependentAssembly></assemblyBinding>
```

警告で言われている通りに、設定を修正します。プロジェクト直下の `Web.config` を開き、下のように修正します。

```Web.config.diff
<configure>
  <!-- 略 -->
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
-        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
+        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
      </dependentAssembly>
```

以上で動作するようになるはずです。

```response.json
[
  {
    "first_name": "Taro",
    "last_name": "Suzuki",
  },
  {
    "first_name": "Hanako",
    "last_name": "Sato",
  }
]
```
背景差分に関する備忘録

##背景差分のアルゴリズム
アルゴリズムにはいろいろな種類がある。
アルゴリズムに関する性能の違いに関しては、「[このサイト](http://whoopsidaisies.hatenablog.com/entry/2018/03/01/130000)」にまとめられているので、詳しくはそこで見てください。C++で書かれているのでpythonの形式に直す必要がある。ちなみに「gt」とは、ground truthのことで理想の結果で人の手で作成したものである。

今回、試したアルゴリズムはMOG2とGSONです。どちらも、findContoursを使い輪郭抽出を行っている。
これらの、アルゴリズムを利用するにはopencv-contribをインストールする必要がある。
pipでインストールすることができる。

```python:example01.py
pip install opencv-contrib-python    
```

###GSON
先のサイトで１番性能の良さそげだったため、最初に試してみた。
pythonの形式に直すのは非常に簡単だった。
このアルゴリズムを利用すると、きれいに物体検出をすることができる。
しかし、このアルゴリズムだと人の影が出てしまう。
fgmaskは２値化された値となっている。

```python:example02.py
fgbg = cv2.bgsegm.createBackgroundSubtractorGSOC()  
fgmask = fgbg.apply(frame)
```

###MOG2
次にMOG２を使ってみた。MOG2を使った理由としては、thresholdを利用して影を消すためである。
２値化されていると、thresholdを用いて影を消すことができない。
人の影を消すには200くらいにしておくと消えるらしい。


```python:example02.py
fgbg = cv2.bgsegm.createBackgroundSubtractorMOG2()  
fgmask = fgbg.apply(frame)
_ , fgmask = cv2.threshold(fgmask,200,255 ,cv2.THRESH_BINARY )
```


###まとめ
GSON,MOG2それぞれを使い、物体検知を行ったがどちら求めている結果をえることができなかった。
GSONの場合、遠いところでの物体検知は良く、検出が途中で切れることはなかった。しかし、影が出てしまうため、二人並んで歩いてしまうとまとめて一つとして検知されてしまう。
一方MOG２は、遠方での物体検知は良くなり、影がなかった分人が重ならない限りまとめて検知されることはなかった。しかし、検出がよく切れ安定しなかった。
対象が絶対に一人だけであれば、GSONを使ったほうがいい。
AfterEffects エフェクト例　オーバーレイ系

###この記事ではエフェクト例をまとめていきます。（随時更新）

この記事に関してはオーバーレイ関係を載せます。
記事の載せ方は
①エフェクトを適用した状態のキャプチャ画面
②適用したエフェクト名と変更したパラメーターのみ記載

##ノイズ系
一瞬の差し込み系やグリッチする時に使おうかな。。。
#####キャプチャ画像
![コンポ 1_[137].png](https://qiita-image-store.s3.amazonaws.com/0/178061/90882cd1-6cca-9609-40d3-c8a206a9ad41.png)

####Target
平面レイヤーにエフェクトを適用
平面レイヤーのモードはスクリーン

#####エフェクト＆パラメーター
エフェクト名■フラクタルノイズ
パラメーター▶コントラスト
変更値▶10000
パラメーター▶明るさ
変更値▶2024
パラメーター▶オーバーフロー
変更値▶3
パラメーター▶トランスフォーム
パラメーター▶
パラメーター▶複雑度
変更値▶10
パラメーター▶サブ設定
パラメーター▶サブスケール
変更値▶10
パラメーター▶
展開expression ↓
エクスプレッション▶time*500
展開expression ↑
パラメーター▶展開のオプション
パラメーター▶ランダムシード
変更値▶1640
パラメーター▶ランダムシード
エフェクト名■輪郭検出
Docker クライアントとDocker サーバを分離した環境を作成したときの話

# 環境情報
最終的なDockerのバージョン
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        67f9a391
 Built:             08/22/2018 09:10:07
 OS/Arch:           windows/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:29:02 2018
  OS/Arch:          linux/amd64
  Experimental:     false

ClientのOS：Windows 10 1803
ServerのOS：Windows 10 1803
#環境構成
[ここ](https://qiita.com/Arturias/items/e13e3ecc39261a258bef)の人と同様、かつ、
Docker ServerをWindowsで作りました。

# 前提
ServerにはWindows Docker をインストールし、サーバー上でDocker コマンドによる
各種動作が実行できていることは確認済み
また、[前記事](https://qiita.com/keigo0502/items/80a41f3c8974ac7986e0)で、
クライアントにはDocker クライアントが導入済みなものとする。

# 設定
サーバ側は、以下の赤枠のチェックボックスをONにしておく。
![docker.png](https://qiita-image-store.s3.amazonaws.com/0/170075/48a1322b-baf1-d184-b1b6-e9c1b95a8acb.png)

クライアント側は以下のように環境変数を設定しておく。
`set DOCKER_HOST=tcp://[サーバのIPアドレス]:2375`

# クライアントからDocker コマンドを実行
環境変数を設定してから、docker psコマンドを実行・・・が、以下のように接続に失敗。
※赤で塗りつぶしているのはサーバのIPアドレス
![docker-client.png](https://qiita-image-store.s3.amazonaws.com/0/170075/2cffc5bf-9f7c-8673-ae44-90213cb1c665.png)

# 調査
サーバ側で拒否されているメッセージなので、サーバ側の受付アドレスを変更すればよいと推測。
が、見つからない。UNIXのDockerにある設定ファイル相当のものが見つからない。

そこで、発想の転換。
設定を変更できないなら、通信をなり済ませてあげればいいじゃない。
外部IPアドレスの特定ポートから来た通信をlocalhostの特定ポートへ変更すればよいのでは？

# ポートフォワーディング
管理者権限のコマンドプロンプトで、以下を実行する

`netsh interface portproxy add v4tov4 listenport=2375 listenaddr=(DockerサーバのIPアドレス) connectport=2375 connectaddress=localhost`

docker コマンドの実行
![docker-client-cmd.png](https://qiita-image-store.s3.amazonaws.com/0/170075/4ab7be1b-031d-13a5-5d67-f96818eafe1c.png)


成功したので、よしとする。

※自分用メモですが、何かあればコメントをお願いします。