OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者向け】TCP/IPとは？

# TCP/IPとは
TCP/IPとは、インターネットなどで標準的に用いられる通信プロトコル（通信手順）で、TCP(Transmission Control Protocol)とIP(Internet Protocol)を組み合わせたものです。ネットワーク同士を繋げるには、みんなが同じ方法で通信しないといけません。そのために通信方式(プロトコル)が決まっています。歴史的には1974年に提案され、パケット交換方式による世界初のコンピュータネットワークであるARPANETに採用されました。それ以来、TCP/IPは通信を実現する基盤技術として使われ続けています。
## IETFとRFC
TCP/IPのプロトコルのほとんどは「RFC(Request For Comments)」と呼ばれる文書にまとめられており、RFCを取りまとめている「IETF(Internet Engineering Task Force)」のサイトから自由に参照できます。誰でも参照できるオープン性も、TCP/IPが普及した要因になったといえます。

# OSI参照モデル
　通信方式の標準的な考え方として「OSI参照モデル」があります。このモデルは国際標準化機構（ISO）によって提唱されており、ネットワークの要素を階層別に分類しているのが特徴です。OSIは開放型システム間相互接続（Open Systems Interconnection）を意味します。プロトコルを階層化することによって、ソフトウェアの開発者はその階層が担う役割に特化した機能のみ開発すれば良いことになります。これにより、実装の容易化とともに責任の区分を明確にできます。
　OSI参照モデルは7つの階層（レイヤ）で構築され、階層が低いほどハードウェアよりの、階層が高いほどソフトウェアよりの処理を行います。各階層の名称と主な機能は以下のようにまとめられます。

![図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646368/2d0982b1-39b7-edb7-a5cf-075de2c65df4.png)

# まとめ
本記事では「TCP/IPとは」について解説をしてきました。通信の手段・規約のことで、コンピュータ同士のネットワークの基礎となっているということは押さえておきたいところです。
【Deno】downloadモジュールでファイルダウンロード

先月にkyを使用したファイルダウンロード方法を公開しましたが、コメントで

> Deno にはファイルダウンロード用のモジュールがあります。
> [download | Deno](https://deno.land/x/download)

とご教示頂いたので、今回はその"download"モジュールを使用したファイルダウンロードを解説します。

# このモジュールについて

downloadは、Denoの`fetch api`をベースにしたURLからファイルをダウンロードすることができるモジュールです。  

# 使い方

mod.tsからdownload関数をインポートして使えます。

```ts
import { download } from "https://deno.land/x/download/mod.ts";

const url =
  "https://raw.githubusercontent.com/denolib/high-res-deno-logo/master/deno_hr.png";
const fileName = "deno.png";
const dir = ".";

await download(url, { file: fileName, dir });
```

実行するときはネットワークにアクセスする権限と書き込み権限が必要なので、オプションに`--allow-net`と`--allow-write`を追加します。

# エラー処理について

エラー処理は、`try/catch文`を使うか、`Promise`の`catch`が使えます。

## try/catch文

```ts
import { download } from "https://deno.land/x/download/mod.ts";

const url =
  "https://raw.githubusercontent.com/denolib/high-res-deno-logo/master/deno_hr.png";
const fileName = "deno.png";
const dir = ".";

try {
  await download(url, { file: fileName, dir });
} catch (err) {
  console.error(err);
}
```

## Promise

```ts
import { download } from "https://deno.land/x/download/mod.ts";

const url = 'https://raw.githubusercontent.com/denolib/high-res-deno-logo/master/deno_hr.png';
const fileName = "deno.png";
const dir = ".";

await download(url, { file: fileName, dir })
  .catch((err) => {
    console.error(err);
  });
```

# やってみる

![deno-download.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457036/b633489a-3b86-23ce-e769-fa85498841c9.gif)

できました:relaxed:

# 環境

```
$ deno --version
deno 1.2.2
v8 8.5.216
typescript 3.9.2
```

# 参考

* <https://deno.land/x/download>
* <https://qiita.com/Seraimu/items/7f443d7dbfe83783d79c> のkerupani129さんのコメント
複数のヒストグラムを重ねて表示する時に、bin幅を統一する方法（matplotlib）

## 背景
forループを使って複数のヒストグラムを重ね合わせて表示する場合、bin幅を指定しないとデータごとに幅が異なり比較しづらかったので、bin幅を統一して表示する方法を調べました。
※自分用のメモなので読みづらかったらすみません

## import・使ったデータセット
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine

wine = load_wine()
df_wine = pd.DataFrame(data=wine.data, columns=wine.feature_names)
df_wine['target'] = wine.target
```
scikit-learnのワインデータセットを使います。
targetという列にはワインの種類を表すラベルを入れました。



## 方法
`plt.hist()`の引数の`bins`にリストを渡すと、リストで指定された値を区間の区切りとしたヒストグラムが描出される。
(`bins=[0,1,2,3,4]`とすると、0～1, 1～2, 2～3, 3～4の4つの区間の棒が描出される）

これを利用して、`np.linspace(最小値, 最大値, 区切りたい数)`でリストを作り、各ラベル用の`plt.hist()`の引数として渡すことで、共通のbinを指定する。


↓bin幅調整なし

```python
feature_name = 'hue'
target_names = df_wine['target'].unique()

for target in target_names:
    plt.hist(df_wine[df_wine.target == target][feature_name], alpha=0.6, label=target)

plt.title(feature_name)
plt.legend()
```
![raw_hist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614475/8983b642-d652-85be-7a3c-5e1e10b3c4ef.png)


↓bin幅調整あり

```python
feature_name = 'hue'
target_names = df_wine['target'].unique()

# 最大値と最小値の間をn_bin等分した幅でヒストグラムの棒を表示するように設定（各targetのbin幅を統一する）
n_bin = 15
x_max = df_wine[feature_name].max()
x_min = df_wine[feature_name].min()
bins = np.linspace(x_min, x_max, n_bin)

for target in target_names:
    plt.hist(df_wine[df_wine.target == target][feature_name], bins=bins, alpha=0.6, label=target)

plt.title(feature_name)
plt.legend()
```

![bin_adjusted_hist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614475/79bd6744-1d46-6eaf-be59-5d7b7d3c29d2.png)


## 参考にした記事
[matplotlibやseabornのヒストグラムでビン幅をサクッとキレイに整える - Qiita](https://qiita.com/matyubara/items/4137acf9cfbdc1dcbab7)
データベーススペシャリスト SQL問題について

# データベーススペシャリストのSQL問題
## 平成３１年春期問１１ を見ていて気になったのです
これってもっといいSQLがあるんじゃない？と
気になったので調べてみました。

社員資格テーブル

| EMPCODE | QUALCODE |
|:-------:|:--------:|
| S001 | AP |
| S001 | DB |
| S001 | FE |
| S002 | FE |
| S002 | SM |
| S003 | FE |
| S004 | AP |
| S005 | « NULL » |


結果

| EMPCODE | 資格1 | 資格2 |
|:-------:|:--------:|:--------:|
| S001 | FE | AP | 
| S002 | FE | NULL |
| S003 | FE | NULL |

上記の社員資格テーブルから結果になるようにデータを抽出するにはどのようなSQLを実行すればよいか？という問題です。

正解は以下のようなSQLになるようにとのことですが、違和感を感じました。

```正解
SELECT C1.EMPCODE, C1.QUALCODE AS 資格1, C2.QUALCODE AS 資格2
FROM 社員資格テーブル C1
LEFT OUTER JOIN 社員資格テーブル C2
	ON C1.社員コード = C2.社員コード
	AND C1.QUALCODE = 'FE' 
　  AND C2.QUALCODE = 'AP'
WHERE C1.QUALCODE = 'FE';
```

確かに上記SQLでも欲しい結果が得られます。
でも、

```突っ込み
SELECT C1.EMPCODE, C1.QUALCODE AS 資格1, C2.QUALCODE AS 資格2
FROM 社員資格テーブル C1
LEFT OUTER JOIN 社員資格テーブル C2
	ON C1.社員コード = C2.社員コード
	（AND C1.QUALCODE = 'FE' ） -- この条件文、いらないんじゃ？ 
　  AND C2.QUALCODE = 'AP'
WHERE C1.QUALCODE = 'FE';
```

C1の集合（外側のWhere文で ’FE’で絞り込まれる） とC2（社員コードと’AP’）の結合なので、外部結合の条件から削除しても結果は同じです。
※設問上、ひっかけ要素として追加しているのだとは思いますが。

ちなみに、実行計画はというと、

```実行計画
SELECT STATEMENT Cost = 6
 +-HASH JOIN OUTER 	 	2 rows (32 bytes) 	1 sec. 	"C1"."EMPCODE"="C2"."EMPCODE"(+)
    +-TABLE ACCESS FULL 	 (SAMPLE.EMPQUAL "C1"@"SEL$1") 	2 rows (16 bytes) 	1 sec.
    +-TABLE ACCESS FULL 	 (SAMPLE.EMPQUAL "C2"@"SEL$1") 	2 rows (16 bytes) 	1 sec.

```

2回、FULL検索が走っていますね。
INDEXや主キーを貼っていないので当然の結果ですが、本来言いたかったことはというと、2回結合する必要ないんじゃない？ということです。

PIVOT使おう！

修正後SQLは以下の通りです。

```
SELECT * 
FROM EMPQUAL C1
PIVOT ( MAX(QUALCODE) FOR QUALCODE IN ( 'FE' AS QUAL_FE ,
                                        'AP' AS QUAL_AP))
WHERE QUAL_FE = 'FE'
```

実行計画

```
SELECT STATEMENT Cost = 4
 +-FILTER 	 	 	 sec.
    +-HASH GROUP BY PIVOT 	 	1 rows (8 bytes) 	1 sec.
       +-TABLE ACCESS FULL 	 (SAMPLE.EMPQUAL "C1"@"SEL$1") 	8 rows (64 bytes) 	1 sec.
```

テーブル検索も1回で済んでいます。
今回のレコード数は少ないので、問題にはならないでしょうが、レコードが増えた場合、ちゃんと考えないといけないですね。
PIVOTや分析関数が出る前は、元のSQLのように各集合を頑張って作って、全部結合して集計して、、、なんてやっていましたが、今は一番コストがかかりやすいデータ抽出を減らせる手段があるので便利な時代になりましたね～。
Rails testで「 FATAL: Listen error: unable to monitor directories for changes.」のエラー

#前提
Rails 6.0.3
ruby 2.6.3

#本題

```
$rails test
```
のコマンドを実行した時に以下のエラーが発生。

```
$ rails test
FATAL: Listen error: unable to monitor directories for changes.
Visit https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers for info on how to fix this.
```

1つのユーザIDに対して生成できるinotifyのインスタンスの数の上限に達してしまったようなことが書かれている？のではないかと思いました。
エラー内容に書いている通り、Githubを確認しコマンドを入力し解決。

##解決方法
ユーザーインスタンスを確認。

```
$ cat /proc/sys/fs/inotify/max_user_instances
```
inotifyのインスタンス上限を変更。

```
$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
```
設定を反映。

```
$ sudo sysctl -p
```
再びコマンド実行。

```
$ rails test
```
【VSCode】カンマ区切りの文字列にする方法

# 概要
SequelProなどで検索した結果のIDなどをカンマ区切りの文字列にしたいこと、業務でよくあります。
僕はエディタはVSCodeを使っていますので、VSCodeを使ったやり方をメモ。
特別な方法ではないので、VSCodeの操作方法が分かっていればできることと思います。

# やり方
SequelProの検索結果をコピーしてVSCodeに貼り付けると、以下のようなスペース区切りの文字列になります。
特定の列だけカンマ区切りの文字列にしたい場合があります。

```
// 例：これの最前列をカンマ区切りの文字列に変換したい
001 hoge fuga
002 hoge fuga
003 hoge fuga
004 hoge fuga
005 hoge fuga
```

1. 変換したい列の一番上の文字の後ろにカーソルを合わせる。

2. 同じ列の一番下の文字の後ろを、`command + option`を押しながらクリック。（マルチカーソル）
　これで変換したい列の全ての文字の後ろにマルチカーソルがある状態になります。
　※一番上か一番下か、カーソルを合わせる順番はどっちでも良い。

3. `shift + command + →`で後ろ側の不要な列を全て選択し、`delete`で削除。 

4. `↓`を一度押し、マルチカーソルが一番上の行には無い状態にする。
　※これをやらないと先頭にもカンマが入る。
　※5より先に（カーソルが文字の後ろ側にある状態で）やらないとマルチカーソルが変なとこまでに入ってしまい、6で一番後ろの文字まで消してしまう。

5. `←` or `control + A`でカーソルを文字の先頭に移動。

6. `delete`を押して改行が無い状態にし、`,`を押す。

7. カンマ区切りの文字列になっている。

※もし真ん中の列をカンマ区切りにしたい場合は、1、２をやる前に同じ方法で消したい列の前側を消しておけば良いです。

## 実演GIF
上記だと手順が多いように見えますが、実際やるのは一瞬です。

[![Image from Gyazo](https://i.gyazo.com/353dbc4465b469fcde31e61d6149b85c.gif)](https://gyazo.com/353dbc4465b469fcde31e61d6149b85c)

# あとがき
正規表現を使って改行をカンマに置換する方法もあるようですが、正規表現考えたりで結局手間かかるので、僕はいつもこの方法でやっています。
この方法だと途中の列をカンマ区切りにする場合も考えずにできるので。
レイマーチングでメンガーのスポンジを描く

前に書きかけだったやつが、いちおうそれなりに形になっていたので公開しちゃいますｗ


## Menger sponge（メンガーのスポンジ）を描く

Wikipediaから画像を引用させてもらうとこんな感じの絵。

![メンガーのスポンジイメージ](https://upload.wikimedia.org/wikipedia/commons/3/3b/Menger.png)

また、文章では以下のように説明されています。

>メンガーのスポンジとは自己相似なフラクタル図形の一種であり、立方体に穴をあけたものである。そのフラクタル次元（ハウスドルフ次元、相似次元）は $\frac {\log 20}{\log 3}(=2.7268\ldots )$ $\frac{\log 20}{\log 3}(=2.7268\ldots )$次元である。メンガーのスポンジの面は同じくフラクタル図形のシェルピンスキーのカーペットでできている。

それをレイマーチングで描き出し、かつきれいな絵にしている作品がこちら。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5616/4d179591-562a-1bfc-5a61-ed8c7e204abb.gif)
- [Visualization Menger sponge](https://www.shadertoy.com/view/3tjGWD)

ちなみに前回は[[GLSL] Shadertoyのシェーダ芸人になるためのTips集](https://qiita.com/edo_m18/items/1532aceb9d470174caaf)という記事も書いたのでよかったら見てみてください。

さて、上記作品のメンガーのスポンジはどうやって描いているのか。それを紐解いてみようと思います。

大枠としての処理はおそらく以下のようなフローで行っていると考えています。

1. 指定サイズ空間での繰り返し（`mod`などを使うリピートパターン）
2. その指定サイズ空間内のXY平面、YZ平面、XZ平面それぞれで一番遠い位置を3点探し、かつそれらの中で一番近い位置を探す（距離関数）
3. (2)で計算したものよりやや小さい空間で同様の計算を行う（ここは複雑さに応じて複数回実行）
4. 最後に、(2)と(3)の計算結果を`max`関数による合成を行う

という手順でフラクタル構造を作っていると考えています。

これを踏まえて、上記フローの(2)と(3)の部分を時間によってモーフィングしてみると以下のような絵が得られます。
小さい空間と大きい空間が複雑にモーフィングしているのが分かるかと思います。

![capture.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5616/a974c7fa-6813-2b44-02ec-b52d9d22dff8.gif)

イメージ的には、各空間ごとに`max`関数で距離を採択しているために、ひとつ分であれば通路のような見た目になるものの、それが複数組み合わさることで距離の算出に差異が出てこうした図が描かれる、という感じでしょうか。（ちょっとまだ頭の中に正確なイメージが湧いていない・・・）

ちなみにこれを、モーフィングではなく`max`関数によって合成すると以下のような絵が得られます。

![max関数による合成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5616/a2caddc0-28a0-abb2-aa25-aaa02c48c964.png)

`max`関数での合成なので、**重なり合っている部分だけ**描かれることになります。

（詳細についてはwgld.orgで解説されているのでそちらを見るといいでしょう→ [オブジェクトの重なりを考慮した描画 | wgld.org](https://wgld.org/d/glsl/g015.html)）

モーフィングの最初と最後だけだとこの形は想像できないですが、おそらく、遮蔽されてしまっている「壁の向こう」ではもう少し複雑な形状になっていることに気づいていないだけかな、と思っています。

これの距離関数のコードは以下です。

```glsl
float s = 10.0;
vec3 p = abs(fract(q / s) * s - s * 0.5); // Repeat space.

// Get maximum distance of surface of cube?
float a1 = max(p.x, p.y); // XY平面で一番遠い位置
float b1 = max(p.y, p.z); // YZ平面で一番遠い位置
float c1 = max(p.x, p.z); // XZ平面で一番遠い位置

float size = 1.0;

// さらにその中で一番近い位置を計算。そこから`size`を引くことで、Void Cubeの距離関数として機能する
float d1 = min(a1, min(b1, c1)) - size + 0.05; // Void Cube.

// --------------------------------------------------------

// もうひとつ、少し小さめのVoid Cubeを計算し、それを最後合成する
s = 1.0;
// 上記のfractを使った計算とやっていることは同じ。2パターン明示。
p = abs(mod(q, s) - s * 0.5); // Repeat space.

// Get maximum distance of surface of cube?
float a2 = max(p.x, p.y);
float b2 = max(p.y, p.z);
float c2 = max(p.x, p.z);

size = 1.0 / 3.0;

float d2 = min(a2, min(b2, c2)) - size + 0.05;

float d = max(d1, d2);

float m = abs(sin(iTime * 0.1));
float r = mix(d1, d2, m);

return r;
```
VBAの備忘録


### 読み取り専用の場合、リジェクトするようにする。

```
Sub Sample_readonly()
　　Workbooks.Open Filename:="C:\Book1.xls", Notify:=False
　　If ActiveWorkbook.ReadOnly Then
　　　　MsgBox "読み取り専用です"
　　　　ActiveWorkbook.Close
　　Else
　　　　Sheets("Sheet1").Activate
　　　　Range("A1") = Now
　　　　ActiveWorkbook.Save
　　End If
End Sub　　　
```

### ファイルオープン例
```

Sub Sample_open()
    Dim buf As String, wb As Workbook
    Const Target As String = "C:\Book1.xlsx"
    ''ファイルの存在チェック
    buf = Dir(Target)
    If buf = "" Then
        MsgBox Target & vbCrLf & "は存在しません", vbExclamation
        Exit Sub
    End If
    ''同名ブックのチェック
    For Each wb In Workbooks
        If wb.Name = buf Then
            MsgBox buf & vbCrLf & "はすでに開いています", vbExclamation
            Exit Sub
        End If
    Next wb
    ''ここでブックを開く
    Workbooks.Open Target
End Sub

```

```

Sub PasteSpacialSample()

    Range("B1").CurrentRegion.Copy  '-----(1)
    
    Range("E1").PasteSpecial Paste:=xlPasteValues   '-----(2)
    
    Range("H1").PasteSpecial Paste:=xlPasteFormats      '-----(3)
    Range("H1").PasteSpecial Paste:=xlPasteColumnWidths '-----(4)
        
    Range("K1").PasteSpecial xlPasteAll, Transpose:=True    '-----(5)
    Range("K1").PasteSpecial xlPasteValues, Transpose:=True '-----(6)
    
    Application.CutCopyMode = False
    
End Sub

```
【Rails】一意性を保つバリデーションの実装

#一意性バリデーションの実装に必要なタスク

1. アプリ側に記述（uniqueness: true）
2. データベース側に記述（unique: true）




#アプリ側に記述
```models/user.rb
validates :email, uniqueness: true
```

#データベース側に記述

```
$ rails g migration add_column_to_users
```

```add_column_to_users.rb
def change
  add_index :users, :email, unique: true
end
```

```
$ rails db:migrate
```

テーブルのカラムに一意性を持たせるには、**インデックスの作成**も必要になる。
理由は、全てのデータを検索することで、過去のデータと重複しているか確認できるため。
cronの起動時刻をランダムに書き替えるワンライナー

小ネタである。

# 前提知識
bashでは、環境変数`$RANDOM`を用いることで、0～32767 の数字をランダムに得ることができる。

例えば、0～3 の数字をランダムに表示するには、剰余演算子記号`%`を組み合わせて次のようにする。

```sh:0～3の数字をランダムに表示
echo $((RANDOM % 4))
```

5～59 の数字ならこうだ。

```sh:5～59の数字をランダムに表示
echo $((5 + RANDOM % 55))
```

この辺の説明は[【シェルスクリプトでランダムにアレをやる】](https://qiita.com/piroor/items/6300e665bc8ac314211b) の方がずっと分かり易かったので、そちらを参照していただきたい。

# cronの時刻フィールドを書き替えるには
本題。
最終行に次の cron が定義されているとする。

```sh
00 2 * * * /home/mindwood/foo.sh > /dev/null 2>&1
```

午前2時に起動する設定だが、これを、午前0時05分～午前3時59分の起動とし、幅を持たせたい。
その上で毎時ジャスト（午前1時、午前2時・・・）は避けたい。

書き替えるワンライナーはこうだ。

```sh
H=$((RANDOM%4));M=$((5+RANDOM%55));sed -i -e '$s/^[0-9]\+ [0-9]\+/'$M' '$H'/' /var/spool/cron/crontabs/root
```

例えば次のように更新される。

```sh
43 1 * * * /home/mindwood/foo.sh > /dev/null 2>&1
```

この時刻が気に入らなければ、何度でもやり直して良い。

なお、`sed`の`$`は最後の行を表す。
`sed`についても、詳しくは [【sedでこういう時はどう書く?】](https://qiita.com/hirohiro77/items/7fe2f68781c41777e507) を参照して欲しい。
Docker Volume の上書きについて

# 前提
- 本記事執筆時の Docker 最新バージョン： 19.03
- 書いている人は、業務で本格的に docker を使ったりしておらず、個人開発で適当に使っていたが、よくわからず使っている部分もあったので改めて調べてるレベル。

# 悩み
[前回](https://qiita.com/aki_55p/items/63c47214cab7bcb027e0) Docker Volume について調べてボリューム完全に理解したと思いながら構築していました。
しかし、単一ボリュームを複数コンテナのディレクトリにマウントする際に、元々コンテナのディレクトリにおいてあったファイルが上書きされたりする挙動を理解していないことに気づき、ちゃんと知っとかないとふとした時にデータ消去とかになったら怖いなと思った次第です。

# 結論
- マウントするボリュームに何かしらファイルやディレクトリが存在すれば、マウントされるコンテナ側のディレクトリの中身は全部上書きされる。
- マウントするボリュームに何も入っていなくて、マウントされるコンテナ側のディレクトリに何か入っていれば、ボリュームにコピーされる。

以上です。シンプル。
以下は実際に上記を確かめてるだけなので、結論以上の情報はないです。

# 試してみる
適当にデータの入ったディレクトリのあるコンテナを2つつくり、それぞれ同じボリュームをそのディレクトリにマウントするように Compose で立ち上げてみて、ボリュームの中身がどうなるか見てみました。

以下のような感じでファイルを用意しました。

```shell-session
volume_test
├── Dockerfile-vol01
├── Dockerfile-vol02
├── docker-compose.yml
├── vol01
    └── file01
└── vol02
    └── file02
```

まず適当にデータを入れたディレクトリだけがあるイメージを作ります。（vol02 は数字変えただけなので省略）

```dockerfile:Dockerfile-vol01
FROM ubuntu:latest

COPY vol01 /vol01

CMD ["bin/sh"]

```
```shell-session
$ docker image build -f Dockerfile-vol01 -t hoge/volcontainer01:latest .
```

そして Compose で2つのコンテナを立ち上げ、データが入ったディレクトリそれぞれに、単一のボリューム（voltest）をマウントします。

```dockerfile:docker-compose.yml
version: "3"

services:
  vol01:
    image: hoge/volcontainer01:latest
    container_name: volcontainer01
    tty: true
    volumes:
      - voltest:/vol01

  vol02:
    image: hoge/volcontainer02:latest
    container_name: volcontainer02
    tty: true
    volumes:
      - voltest:/vol02

volumes:
  voltest:
    driver: local
```
```shell-session
$ docker-compose up -d
```

この時、`voltest`の中身はどうなっているのか。

```shell-session
$ docker container exec -it volcontainer01 ls vol01
file01
```
`file01` だけが入っており、`vol02`の方に入っていた`file02`は入っていません。
これは流れ的には、`volcontainer01`が立ち上がった時に`voltest`ボリュームが生成され、`vol01`に入っていた内容がコピーされます。
その後`volcontainer02`が立ち上がって`vol02`に`voltest`ボリュームがマウントされる際に、`voltest`にはすでにファイルが存在するので、`vol02`の中身をまるごと上書きしているということです。

ちなみにこの時、もし`vol01`に何も入っておらず、`vol02`にだけファイルが入っていた場合は、`vol02`にマウントする時点で中身がコピーされるため、`voltest`には`file02`が入った状態になります。

では試しに、このまま`voltest`の内容を変更してから Compose を削除し、再度立ち上げてみましょう。

```shell-session
$ docker container exec -it volcontainer01 rm vol01/file01
$ docker container exec -it volcontainer01 touch vol01/addfile
$ docker-compose down
$ docker-compose up -d
```
この時、`voltest`の中身はこうなっています。

```shell-session
$ docker container exec -it volcontainer01 ls vol01
addfile
```
ボリュームはデータの永続化のための仕組みなのでコンテナが破棄されても残ります。
再度 Compose でコンテナを立ち上げると、今度は`voltest`には既に先程入れたファイルが存在しており、`vol01`の内容も`vol02`の内容も上書きしてしまうためです。

ということで、繰り返しになりますが、

- マウントするボリュームに何かしらファイルやディレクトリが存在すれば、マウントされるコンテナ側のディレクトリの中身は全部上書きされる。
- マウントするボリュームに何も入っていなくて、マウントされるコンテナ側のディレクトリに何か入っていれば、ボリュームにコピーされる。

ということが確認できました。

# 参考文献
- [公式ドキュメント](https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/)
オリジナルのアプリを完成させるまでの解説

#環境
macOS 10.15.5
Rails 5.2.4.2
Docker 19.03.12

#概要
オリジナルアプリの概要はCRUDのシステムを意識した簡易的なメモアプリの開発です。
簡易的なアプリと言っても実用性には欠かないよう注意を払いました。行数が増えてもレイアウト崩れが起きないように実装し、文字数制限や空白の項目が新規作成されないようにも設定しました。

Dockerを用いてフレームワークはRailsを使用しました。そしてHerokuにより公開をしています。

#オリジナル性について
HTMLに関してはclass名などは学習サイトをヒントに用いて、デザインは外観は学習サイトをヒントにしましたが実装は全て自走で行いました。
Railsの機能の実装に関して事前に学習サイトを何度も繰り返し行い、CRUDの機能を頭に入れてから今回の作成を行いました。そのため短いコードなどはなるべくサイトなどを参考にせず、自分で覚えた内容で実装し、コマンド操作は基本的に全て頭に入れた内容のみで行いました。


#サイトについて
<img width="1440" alt="スクリーンショット 2020-08-01 23.23.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587506/f09e86db-4714-b7d4-3d36-1096ce283f98.png">
一覧ページをトップページとして定めメモの項目が個々の詳細が表示できるようにリンク指定をしています。その際に新規投稿された項目が最上部に移動するように実装しました。

```ruby:lists_controller.rb
class ListsController < ApplicationController
  def index
    @lists = List.all.order(created_at: :desc)
  end
```

###新規作成ページ
<img width="1440" alt="スクリーンショット 2020-08-01 23.23.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587506/b63ac951-1de5-8f33-90ec-54b6c25cf13c.png">
新規作成ページでは空白の内容と141文字以上の内容が実行されないように設定しています。

```ruby:list.rb
class List < ApplicationRecord
  validates :content, {presence: true, length: {maximum: 140}}
end
```

###詳細ページ
<img width="1440" alt="スクリーンショット 2020-08-01 23.24.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587506/a65115e4-0f53-1694-0b26-98685ed6ebec.png">
メモ一覧の個々の項目のリンクから移動すると個々の詳細ページが閲覧できます。そこから「編集」と「削除」を実行することができます。

###編集ページ
<img width="1440" alt="スクリーンショット 2020-08-01 23.24.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587506/014a7b4a-7d03-6975-ff32-db723f815fbf.png">
編集ページではページを開いたときに編集前の内容が表示されるように実装しています。

```ruby:edit.html.erb
<div class="form-bady">
  <textarea name="content"><%= @list.content %></textarea>
  <input type="submit" value="編集">
</div>
```

```ruby:lists_controller.rb
def edit
  @list = List.find_by(id: params[:id])
end
```

#オリジナルアプリを作るにあたり意識したこと
わたしは自走できるエンジニアとしてスキルを身に付けたい！という思いからどんなやり方がそんなエンジニアに近づける方法なのか良く自問自答をします。今回このシンプルなメモアプリを作成しようと考えたのはRailsのCRUDの機能やMVCは完璧に落とし込もうと考えたのでこのシンプルさにまとめてみました。
今後はログイン機能やユーザーごとのアクセス権限を設けたページの作成などの機能を有したアプリの作成などにも取り組みたいです！
qmk_firmwareでバッククオート（`）を入力する方法

## 問題点
[qmk_firmware](https://beta.docs.qmk.fm/using-qmk/simple-keycodes/keycodes) だと「KC_GRV」がバッククオートのキーコードとなっています。
しかし、実際に書き込むと何故かESCと認識されバッククオートが入力できません。

## 解決策
us配列だと「option + ~」（jis配列だと「shift + @」）でバッククオートが入力できるため、

```
#define KC_BQ LALT(KC_TILD)
```  
と宣言してあげればバッククオートが入力できるようになります。
Apache2 の VirtualHost の SSL で CGI を使う

確認した Apache2 のバージョン

```text
$ apache2ctl -v
Server version: Apache/2.4.41 (Ubuntu)
Server built:   2020-04-13T17:19:17
```

1) まず、CGI が VirtualHost で使えるようにします。

例えば、test.example.com ならば

/etc/apache2/sites-available/test.example.com.conf
というファイルを作成し、設定を記述します。

```text:/etc/apache2/sites-available/test.example.com.conf
<VirtualHost *:80>
（省略）
    <Directory /var/www/html/public_test>
        Options +Includes +FollowSymLinks
        Options +ExecCGI -MultiViews
        AllowOverride none
        AddHandler cgi-script .pl .cgi .py
        Require all granted
        AddType text/html .html
        AddOutputFilter INCLUDES .html
    </Directory>
</VirtualHost>
```

/etc/apache2/sites-enabled にシンボリックリンクを作成します。

```bash
cd /etc/apache2/sites-enabled
sudo ln -s ../sites-available/test.example.com.conf .
```

設定の確認

```bash
sudo apache2ctl configtest
```

Apache2 を再起動して、cgi が動くのを確認

2) Let'Encrypt で SSL 化します。

/etc/apache2/sites-available/test.example.com-le-ssl.conf
が作成され、
/etc/apache2/sites-enabled にシンボリックリンクが作成されます。

3) SSL でアクセスすると、cgi が 使えません。

4) /etc/apache2/sites-available/test.example.com-le-ssl.conf に cgi が動く設定を、test.example.com.conf からコピーします。

```text:/etc/apache2/sites-available/test.example.com-le-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
	ServerName test.example.com
	DocumentRoot /var/www/html/public_test

    <Directory /var/www/html/public_test>
        Options +Includes +FollowSymLinks
        Options +ExecCGI -MultiViews
        AllowOverride none
        AddHandler cgi-script .pl .cgi .py
        Require all granted
        AddType text/html .html
        AddOutputFilter INCLUDES .html
    </Directory>

SSLCertificateFile /etc/letsencrypt/live/test.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/test.example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
```

5）Apache2 を再起動すれば、ssl で CGI が使えます。
MAMPでバーチャルホストを設定する


#やったこと
###バーチャルホスト設定を有効化する

"C:\MAMP\conf\apache\httpd.conf"を設定
初期設定は"Include conf/extra/httpd-vhosts.conf"が無効になっているので有効にする。

```
# Virtual hosts
Include "C:\MAMP\conf\apache\extra\httpd-vhosts.conf"
```

###ホストの設定
"C:\MAMP\conf\apache\extra"にC:\MAMP\bin\apache\conf\extra\httpd-vhosts.conf"をコピー
下記のように設定

```
<VirtualHost *:80>
    DocumentRoot "C:\MAMP\htdocs\fanawill"
    ServerName local-fanawill.com
    <Directory "C:\MAMP\htdocs\fanawill">
        AllowOverride all
    </Directory>
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "C:\MAMP\htdocs\xxxxxx"
    ServerName local-xxxxxx.com
    <Directory "C:\MAMP\htdocs\xxxxxx">
        AllowOverride all
    </Directory>
</VirtualHost>
````

###hostsの設定
"C:\Windows\System32\drivers\etc\hosts"に下記を追加

```
127.0.0.1       local-fanawill.com
127.0.0.1       local-xxxxxx.com
```

#参考
[MAMPを使って複数バーチャルホストのローカル環境を設定する](https://qiita.com/eryuus1/items/9300e6d56729799bae5d)
Gurobipyでアカデミックライセンスの期限が切れた場合


# はじめに

Gurobiはどうやらアカデミックライセンスの期限がかなり短いらしいです。
定期的に更新する必要があります。


# 手順

[こちらの記事](https://qiita.com/keisukesato-ac/items/b0425a879622b99a2610)を参考にすることで、すでにアカデミックライセンスを持っているはずです（切れた場合を想定しているため）。


そのため、この切れたライセンスを更新します。

https://www.gurobi.com/downloads/free-academic-license/#show_instructions

上記のURLの「Installation」に書いてある

```
grbgetkey random-id-str(此処は４０文字ぐらいのランダム文字列が書いてあります)
```

を自分のPCのターミナルに貼ってください。

これで更新が完了します。
railsで動画を投稿する

今回、初投稿させていただきます。
少し、見にくかったりしてもご了承お願いします。

今回は、railsで動画アップロード機能の備忘録となっております。
個人的にFFmpegを使用した動画アップロードが分かりにくかったので、なるべく分かりやすく説明できればと思います。

#環境
Ruby 2.6.5
Rails 6.0.3.2

#早速取り掛かっていく

```ruby:ターミナル
rails new RailsApp
```
ターミナルでRailsAppを作ります。

```ruby:Gemfile
gem 'carrierwave'
gem 'mini_magick'
```
Gemfileに追記

```ruby:ターミナル
rails bundle install
```
ターミナルでbundle installします。

```ruby:ターミナル
rails g uploader video
rails g scaffold post video:string
```
ターミナルでuploaderとscaffoldを作成

```ruby:ターミナル
rails db:migrate
```
忘れずにマイグレーション

```ruby:app/models/post.rb
mount_uploader :video, VideoUploader
```
post.rbに追記

```ruby:app/uploaders/video_uploader.rb
def extension_whitelist
   %w(jpg jpeg gif png MOV wmv mp4)
end 
```
38行目からコメントを外して、追記

```ruby:views/posts/_form.html.erb
<div class="field">
    <%= form.label :video %>
    <%= form.file_field :video, :accept => 'video/*' %>
</div>
```
text.fieldになっていると思うので、file.fieldに書き換える。

```ruby:app/views/posts/show.html.erb
<p>
  <%= link_to @post.video_url.to_s do %>
   <%= video_tag(@post.video.to_s) %>
  <% end %>
</p>
```
<%= @post.video %>になっていると思うので書き換えます。
<%= link_to @post.video_url.to_s do %>を書かないと動画をクリックしても再生されません。

#ありがとうございました
動画アップロードに悪戦苦闘したので、皆さんが簡単にできたら幸いです。
複数の要素をスクロール検知してアニメーションを行う

よくポートフォリオサイトなどで見かけるスクロールすると画像がフェードインしてくる感じのものが作れます。

## IntersectionObserver
".made-item"が付いている要素を取得して、それぞれの要素が特定のスクロールポイントに来たときにclassを付与、消去するプログラムです。

```js
function() {
      const items = document.querySelectorAll('.made-item')
      const cb = function(entries, observer) {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            console.log('はいったときの処理');
            console.log(entry.target);
            entry.target.classList.add('inview')
          } else {
            console.log('でたときの処理');
            entry.target.classList.remove('inview')
          }
        })
      }
      const options = {
        root: null,
         //交差する要素を設定できる 変更することはあまりない
        rootMargin: '0px 0px -300px 0px',
        //交差点の場所をmarginのように指定できる
        threshold: 0
        // 初期値は0 0は交差点に入ってくる要素の下の部分 1は上の部分でcbが呼ばれる
        // 配列で[0, 0.5, 1とすると要素の上、真ん中、下でそれぞれcbが呼ばれる
      }
      const io = new IntersectionObserver(cb, options)
      items.forEach(item => {
        io.observe(item)
     // io.observe(item2)
     // io.observe(item3)
     // ioの中に↑こんな感じで要素を複数入れられます
      })
    }
```
- querySelictorAllで複数のclassを指定
- forEachでそれを回して変数io(newしたIntersectionObserver)に代入
- 上記の要素がcbの引数entriesに入るので入ったとき、出たときの処理を記入
- 交差点の要素はentry.targetで確認できる


## scrollY
```js
let scroll = 0
function() {
    scroll = window.scrollY
    console.log(scroll);
    }
```

- スクロールで上端からのピクセル数を検知
Goのldapモジュールで認証をLDAP認証をかける

## 認証したいユーザー

- `cn=yuta`

## ldapモジュールをインストール

```bash
go get github.com/go-ldap/ldap
```

## サンプルコード

```golang

package main

import (
	"fmt"
	"github.com/go-ldap/ldap/v3"
	"log"
)

var (
	ldapServer = "ldap://localhost:389"
	baseDN     = "dc=vamdemic,dc=black"
	username = "yuta"
	password = "password"
	bindusername = "cn=admin,dc=vamdemic,dc=black"
	bindpassword = "password"

)

// This example shows how a typical application can verify a login attempt
func Example_userAuthentication() {
	l, err := ldap.DialURL(ldapServer)
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()

	// First bind with a read only user
	err = l.Bind(bindusername, bindpassword)
	if err != nil {
		log.Fatal(err)
	}

	// Search for the given username
	searchRequest := ldap.NewSearchRequest(
		baseDN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		fmt.Sprintf("(&(objectClass=organizationalPerson)(cn=%s))", username),
		[]string{"dn"},
		nil,
	)

	sr, err := l.Search(searchRequest)
	if err != nil {
		log.Fatal(err)
	}

	if len(sr.Entries) != 1 {
		log.Fatal("User does not exist or too many entries returned")
	}

	userdn := sr.Entries[0].DN

	// Bind as the user to verify their password
	err = l.Bind(userdn, password)
	if err != nil {
		log.Fatal(err)
	}

	// Rebind as the read only user for any further queries
	err = l.Bind(bindusername, bindpassword)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	Example_userAuthentication()
}

```
非同期の双方向更新を実現するためのテクニック

近年、Fluxのように双方向の更新を極力避けて、単方向の更新に還元させようという流れがあります。ただ、どうしても双方向の更新が避けられない場合はあるでしょう。Goole Docsのように、複数の人が同じドキュメントを編集する場合。画面上の複数の入力コンポーネントが相互に同期しているような場合です。

特定の言語に依存しない話ですが、Javascriptで使うことが多いとは思われるため、タグにJavascriptを入れています。

# 1. 一番単純な実装

まず、一番シンプルに、Aが更新されたらBに反映させる、Bが更新されたらAに反映させる、という実装を考えます。

#2. 外部から更新を受け入れた場合は、更新の報告をしない

この際、単純に実装するとA→B→A→Bという無限ループになってしまいます。これを解決するためには以下のような方法が考えられます。

それは、「外部から更新を受け入れた場合は、更新の報告をしない」ことです。

#3. サーバ側でupdateIdを管理し、最後のコミットを反映させる

ただ、これだと、AとBが同時に更新した場合、最終的に、どちらのサーバ反映が早かったかに関わらず、AではBが反映され、BではAが反映されることになります。つまり、AとBの現在状態がずれてしまいます。

これに対応するためには、サーバ側で、更新の受付を管理し、最新の状態を確定させる必要があります。

これは、socket.ioを使う場合、フレームワーク側で更新順序の管理するので、サーバ側で特別な対応は不要です。

この場合、クライアント側では、自分が行った更新がサーバを通して通知されてきた時に無視せずに、受け入れるような実装が必要です。自分が行った更新がサーバを通して通知されてきた時に無視するような実装にすると、更新がAとBで同時に行われて、Aの方が先にサーバに到達した時、本来、現在状態はBの更新でなければいけないのに、Bの側ではそれを受け取れず、現在状態がずれてしまいます。

# 4. 更新中の通知の無視

しかし、これにはまた問題があります。
自分が行った更新がサーバを通して通知されてきた時に受け入れるとなると、
そのラウンドトリップの間に行われた変更が一時的にであれ破棄されることになってしまいます。
これは、ユーザから見ると、行った変更が一時的に巻き戻されるように見えることになり、
受け入れられるものではありません。

これを解決するための方法は、

「自分が更新を行ってそれが通知されるまでの間、更新の受け入れを先延ばしする」

ことです。

# 5. 更新中の自己更新の無視

しかし、これにもまた問題があります。それは、外部からの更新の受け入れもストップしてしまうため、AとBがずっと更新し続けると、永遠にAとBの状態がずれたままになることです。

これを解決するには、上のルールを以下のように修正すれば良いことになります。

「現在状態が、自己の更新の結果によるものである場合、自分が行った更新の通知は無視する」

つまり、自分が更新をしている間でも、他の人の更新は受け入れます。そして、いったん他の人の更新を受け入れれば、その後に到着した自分が行った更新は受け入れます。

これで初めて、現在状態のズレがなくなり完全な同期が実現することになります。

# 6. まとめ

こうやって見ると、双方向更新を実現するため考慮しないといけないことが想像以上に多いことが分かると思います。

ここから分かる重要なことは、双方向更新が必要になったとき、一番最初に考えないといけないことは「双方向更新をしないで良いように設計できないか検討すること」です。そして、Firestoreのような既存サービスの利用を検討すること。それがどうしても無理だった場合、この記事のことを思い出してもらえると幸いです。
極限まで単純化したPromiseのサブセット

例外処理等はなく、とにかくthenableにすることだけに特化したPromiseのサブセットです。あまり実用的な意味はありませんが、Promiseの内部の実装を理解する上で参考になればと思います。

```js
const Promise = window.Promise || function Promise(executor) {
  const callbacks = [];
  let isResolved = false;
  let resolvedValue = null;
  const resolved = (value) => {
    isResolved = true;
    resolvedValue = value;
    callbacks.forEach(callback => callback(resolvedValue))
  }
  const rejected = (err) => {
    callbacks.splice(0);
    console.error(err);
  }
  executor(resolved, rejected);
  this.then = (callback) => {
    if (isResolved) {
      callback(value);
    } else {
      callbacks.push(callback);
    }
  };
}
```
SQL文で変数を使う方法 in JavaScript

# はじめに
Node.jsでExpress+Mysqlを用いてRestApiを作成する際、postでの処理に詰まったため備忘録として記事を書きます。

# 問題

|id(int)|name(String)|
|---|---|
|1|test|

このようなテーブルに対して、以下のソースを用いてpostでレコードを挿入する際、数値は入るが文字列はエラーが出て入れることができなかった。

```sample.js

id=req.body.id; 
name=req.body.name"; 

//jsonで{id:2,name:”sample”}というデータを送信

sql="INSERT INTO api_tbl VALUES("+id+","+name+")";
connection.query( sql,function (error, results, fields) {
   if (error) throw error;
   res.send("ok");
});
```
原因としては、postリクエストを送った際、sql文をセットしている変数`sql`に以下のような文字列が格納されていたからと考えた。

`sql="INSERT INTO api_tbl VALUES(2,sample)"`

ここからnameの文字列を「""」で囲うために、変数`name`の値を以下のように書き換えることで実装できた。

`name= '"'+req.body.name+'"'`

# おわりに
SQL文はあまり学習していないので変なところで詰まってしまった…反省。
基本的な構文はすらすら書けるようしっかり学習します。
今回の手法、もっと簡単にできるやり方があったら教えてください！

(2020/8/2　追記)
@nagtkk さんのコメントで、プレースホルダ（`?`）をつかってsql文に値をセットするやり方を教えてもらいました！
実際に試してみたらしっかりと動作し、またソースも見やすく簡単に実装できたためこちらの手法を推奨します。
has_manyとbelongs_toの使い方

#プログラミングの勉強日記
2020年8月2日　Progate Lv.226
`has_many`と`belongs_to`の使い分けに戸惑った。`has_many`のときに複数形にするのを忘れてしまい、うまく実行されなかったので、`has_many`と`belongs_to`についてまとめる。

#関連付け(アソシエーション)とは
　2つのテーブルを関連付けさせること。テーブル間の関係をモデル上の関係として操作する仕組み。
　テーブル同士の関係には「1：1」「1：多」「多：多」の3つの関係が存在する。今回は「1：1」「1：多」の関係を表すときに使う`has_many`と`belongs_to`についてまとめる

　今回は、UserテーブルのidをPostテーブルと関連付けをして、誰の投稿かわかるようする。

#has_manyとは
　`has_many`は「1：多」の関連付けを表し、〇〇が複数の〇〇を所有しているという関係を表す時に使う。関連付けをすることによって、データをまとめて扱えるようになるので、より効率的にデータベースを操作することができる。


```ruby:models/user.rb
class User < ApplicationRecord
  has_many :posts
end
```
　<font color=blue>`has_many`を使うときは複数形にする</font>

#belongs_toとは
　`belongs_to`は「1：1」の関連付けを表し、〇〇が◯◯に従属するという関係を表す時に使う。


```ruby:models/post.rb
class Post < ApplicationRecord
  belongs_to :user
end
```
　<font color=blue>`belongs_to`を使うときは単数形にする</font>
[Unity]UniRxとZenject(Extenject)で実行環境に応じたユーザー操作を監視して自機を動かす

## はじめに
Unityの開発ではいろいろと便利なアセットが公開されていますが、そのうちUniRx, Zenjectについて理解を深めておこうと思いました。
わかってはいましたが、これが非常に奥が深く…これはとにかく使ってみないとわからんと思い至り、表題の内容で実際に使ってみたのでその記録を残しておきます。
(個人的な備忘録・頭の整理の側面が強いです)

### 環境
- Unity : 2019.3.0f6 64bit
- UniRx : 6.2.2
- Zenject(Extenject) : 9.1.0

### 書いた内容
- やろうとしたこと
- やってみたこと
 - Zenjectを用いた動的な入力方法切り替え
 - UniRxを用いた各種操作の監視
- まとめ

## やろうとしたこと
とりあえずこんな感じのシーンをえいやと描いて、自機(真ん中の紙飛行機)を左右に動かしてみようと思いました。
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474074/f2021e21-6d38-cf57-f944-945c0388e7a2.jpeg)
自機を動かす入力方法を以下のように切り分けます。
・Android/iOS端末では画面のボタンで操作
・PCなどではキーボードの左右キーで操作

## やってみたこと
### Zenjectを用いた動的な入力方法切り替え
何はともあれ(？)以下の記事を何度も読んで、Zenject(今はExtenject)の導入に限らず疎結合な設計とインターフェースについて知見を得ました。

参考：[Zenject入門その1　疎結合とDI Container](https://qiita.com/toRisouP/items/b3d3c43db40857ca4ad4)

今回自分がやろうとしていることに当てはめるとこんな感じになりそうです。
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474074/073b137f-bbef-ce10-eb7b-af6ed2971e23.jpeg)
・Playerは左右に移動するだけなのでIInputProviderに用意するIFはGetMoveのみ
・タッチ入力とキーボード入力を担当するInputProviderについて環境に応じたものをBindする(Zenject)

上記に追加で調べて対応した内容としては
・同じ型のButton2つをBindする際はIDを指定すれば別々にBindできる
・Monovihaviourでなくてよいクラスは継承を外し、コンストラクタで参照先をBindする
といった点がありました。
コンストラクタインジェクションだと`[Inject]`アトリビュートおよび`using Zenject;`が不要なので、Zenjectなしの環境に対する可搬性が高いです。
(ただしID指定している場合は`[Inject(Id = xxx)]`表記が必要…)


これでやりたいことはだいたい実現できますが、個人的に少し気になった点がありました。それは**Playerが毎フレーム(Updateのたびに)「そのフレームで左右移動の操作がされているか」をGetしに行く**という構図です。
このような構図は様々なところで目にしますが、個人的にPlayerがUpdate関数でポーリングするのではなく、**各種操作が実行された際にPlayerを動かす**というイベントドリブンな構成にもしてみたいと思いました。

### UniRxを用いた各種操作の監視
前述のZenject入門記事を書かれたtorisoupさんのスライドで紹介されている内容を参考に、自分もMVPモデルを意識して構成を見直しました。

参考：[UniRxでMV(R)Pパターンをやってみた](https://www.slideshare.net/torisoup/unirxmvrp)

・Presenter新規追加
・uGUIボタン・キーボード操作をPresenterが監視し、操作があったらPlayerに反映する
・各種入力および操作はUniRxの仕組みでSubscribeすることで監視下に入る
・InputProviderおよびPlayerはPresenterを参照しない
・Presenterは各種入力およびPlayerを参照する　この参照にDIを用いる

こんな感じになりました。
![3_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474074/06a950fd-1243-20f9-a957-4df497bd78c4.jpeg)

~~前の構成ではIInputProviderというinterfaceがあり、いい感じに動的なBindがされていたのですが…
今回の構成ではInputProvider側で公開するのがIObservable<T>プロパティでありメソッドではないのでinterfaceにできず、Baseクラスという位置づけにしました。~~
[2020/8/2訂正]
interfaceはプロパティを持つことができるのでIInputProviderのままで実装できました。

あとはクラス図の構成で実装を進め、ZenjectのScene ContextとInstallerを作成して(すみませんこのあたりの詳細は割愛)動作確認です。
![4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474074/86757b65-9b18-7863-6e4b-0bcd73da6698.gif)
※Editorですが画像取得のためuGUI入力有効にしてあります


よかった動きました(＾＾)それにしてもシンプルな…

ソースコードなどはGithubに置いてあります：
https://github.com/zeffy1014/Unity_InputPractice

## まとめ
今回の一連の学習では

- UniRxによる各種操作の監視
- Zenjectによる動的な監視対象の紐づけ

について軽くかじって咀嚼・消化することができたかなあと思います。幸いアレルギーは出なかったので、この辺りを足がかりにUniRX, Zenjectの他機能についても使えるようになれればと考えています。

ただ注意すべきは、UniRxやZenjectを使うことが目的になってはいけないということで。
何よりもまずはよりよい設計を意識し、それでUniRxやZenjectが必要になったら使うのだぞということを常に頭に置いておこうと思います。


以上です。
バリデーションの検証ツールについて簡単にまとめてみた！(テキストのみ)

##accept

- 主にチェックボックスに使う。
- true、on、yes、1の値かどうか判断できる。 
- チェックされているかどうかの処理を実行できる。

##active_url、url
- active_urlはアドレスで指定されたドメインが実際に有効かどうかをチェックできる。(dns_get_record関数でDNS情報を取得し、有効なIPアドレスかどうかをチェック)
    - https://www.php.net/manual/ja/function.dns-get-record.php (dns_get_record関数については公式リファレンス参照)

- urlはurlの形式で書かれているかどうかをチェック。


##after: 日付、 after_or_equal: 日付
- afterは指定した日付よりも後かどうかをチェックする。
- after_or_equalは指定した日付と同じかそれよりもあとであるかチェックできる。

(これらは「:」の後に日付を表す文字列をつけて利用します。あるいは、日付を入力する他のフィールド名を指定することもできる。)

##before: 日付、 before_or_equal: 日付
- beforeは指定の日付より前かどうかをチェックできる。
- before_or_equalは指定の日付と同じかそれより前であるかをチェックできる。

これらはafterの反対です。
日付についてはafterと同じです。

##alpha、alpha-dash、alpha-num
- alphaは入力したテキストが全て「A~Z(a~z)」であるかチェックできる。
- alpha-dashは「A~Z(a~z)」と「-」と「_」であるかチェックできる。
- alpha-numは「A~Z(a~z)」と数字であるかをチェックできる。

##array
- フィールドが配列となっているかどうかをチェックできる。

##between: 最小値, 最大値
- 数値のフィールドで用いる。
- 値が指定の範囲内かをチェックできる。
- betweenの後には、最小値と最大値を「,」で区切って記述しておく。

##boolean
- 値が真偽値かチェックできる。
- true、false、0、1といった値であれば判別できる。(それ以外は不可)

##date、date_format: フォーマット
- dateは入力されたテキストが日時の値として扱えるものかをチェックできる。これはstrtotime関数でタイムスタンプに変換できればOKです。(https://www.php.net/manual/ja/function.strtotime.php strtotime関数については公式リファレンスを参照)
- date_formatは、入力された値が指定フォーマットの定義に一致しているかどうかをチェックします。フォーマットに沿った形式ならばOKです。

##different: フィールド、 same: フィールド
- 指定されたフィールドと同じ値かどうかをチェックできる。
- differentは異なる値であればOKです。
- sameは反対に同じ値ならばOKです。

##digits: 桁数、 digits_between: 最小桁数, 最大桁数
- 数値で使う。
- 入力された値が指定された桁数かチェックできる。
- digitsは指定の桁数ならばOKです。
- digits_betweenは最小桁数〜最大桁数の範囲内であればOKです。

##distinct
- 配列として用意されている項目で使う。
- 配列内に同じ値がないかチェックできる。(同じ値が複数あった場合不可)

##email
- 電子メールアドレスの形式かチェックできる。
- これは形式をチェックするだけで実際にそのアドレスが使えるかはチェックしない

##exists: テーブル, カラム
- データベースを利用する場合に使われる。
- 入力された値が指定のデータベースの指定のカラムにあるかどうかをチェックできる。(あればOK、なければ不可)

##filled、 required
- filledはその項目が空でないかチェックできる。(入力されていれば不可)
- requiredはそれが必須項目であることを示す。(入力されていればOKです)

##image
- ファイルのフィールドで指定します。
- 指定されたファイルがイメージファイルかどうかをチェックできる。

##in: 値１, 値2, ・・・・・、not_in: 値１, 値2, ・・・・・
- inは入力された値がin: ・・・・・に用意した値に含まれているかチェックできる。
- not_inは逆です。

##integer、 numeric
- integerは値が整数であることをチェックできる。
- numericは値が数値であることをチェックできる。

##ip、 ipv4、 ipv6
- 値がIPアドレスかどうかチェックできる。
- ipv4はIPアドレスの中でipv4かどうかチェックできる。
- ipv6はIPアドレスの中でipv6かどうかチェックできる。

##json
- 値がjson形式の文字列かどうかをチェックできる。

##min: 値、 max: 値 
- 値が指定よりも大きいか小さいかをチェックできる。
- minは指定の値よりも小さい、maxは大きいかをチェックできる。
- 最大か最小かを調べる場合は前述したbetweenを使う。

##regix: パターン
- 指定した正規表現パターンにマッチするかチェックできる。

##size: 値
- 値の大きさをチェックできる。
- 文字列ならば文字数、数値の場合は整数値、配列の場合は要素の数をチェックできる。

##string
- 文字列の値かどうかをチェックできる。

##unique: テーブル, カラム
- データベース利用の際に用います。
- 指定のテーブルの指定のカラムに同じ値が存在しないかチェックできる。

---
学習のまとめとして書いてみました。
もし間違いや記述が古いなど指摘をいただけますと幸いです。
AWS EC2のDedicated Hostsとハードウェア専有インスタンスの違い

## 概要

EC2における以下2つの違い。ソリューションアーキテクトの模擬試験などで頻繁に出るが毎回忘れるため自分用メモ。

 - Dedicated Hosts
 - ハードウェア専有インスタンス(Dedicated Instances)

## 要点

 - Dedicated Hosts、ハードウェア専有インスタンスともに__ハードウェアを専有できる__オプション。
 - Dedicated Hostsは__どのハードウェアで起動するかを固定すること__ができる。
 - 一方、ハードウェア専有インスタンスは__ハードウェアの固定はできない。__

## 用途
 - Dedicated Hostsは、__ソフトウェアライセンスがハードウェアに依存する__場合や__BYOL(Bring Your Own License)__で利用。
 - ハードウェア専有インスタンスは、__コンプライアンス要件などで他人と異なるサーバで起動する必要がある__場合などに利用。

## 補足

公式ドキュメントにより詳細な違いがある。今回はわかりやすい部分を記載した。
[Dedicated Hosts](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/dedicated-hosts-overview.html)
samba用のユーザをパスワード付きでシェルスクリプトを用いて登録する

# 背景
世間的にどの程度ファイルサーバとしてsambaを利用しているか分からないが、自身の環境ではsambaを用いてファイルサーバを構築していた。
頻繁に社員の出入りがある関係でsambaのユーザをアクセス権制御を目的として登録や削除を行なっていたのだが、手入力で毎日大量のユーザを登録・削除することに嫌気がさしたため簡単なスクリプトを作った。

# 環境
- OS  
Amazon Linux 2
- samba  
Version 4.10.4

# 事前準備  
以下のコードをコピペで利用する場合は事前に`/tools/usrpass.list`を作成しておくこと。中身は以下のように１行ごとにユーザアカウント名とパスワードをスペース区切りで事前に用意しておく。

```
tanaka hogehoge
sato fugafuga
```

# コード
基本的な動作としては以下の通り。

- リストからユーザを１行ずつ読み込む
- 読み込んだユーザ名とパスワードは各変数に代入
- 既にユーザが登録されている場合にはユーザ登録をスキップ
- 未登録ユーザの場合はsmbpasswdを使ってユーザ登録とパスワードを同時に実行

```
#!/bin/bash
while read line
do
  #echo $line
  #リストを１行ずつ読み込んでIDとパスワードを変数に格納
  usrname=`echo $line | awk '{print $1}'`
  passwd=`echo $line | awk '{print $2}'`

  #既存のユーザでないか確認するための１行
  pdbedit -L -w | egrep "^""$usrname"":" >> /dev/null
  
  #既存ユーザの場合は登録処理をスキップ、未登録の場合はワンライナーで登録
  if [ $? == 0 ] ; then
  	echo "$usrname is already registered."
  else
  	echo "Set $usrname registration and password"
  	(echo $passwd ; echo $passwd) | smbpasswd -s -a $usrname
  fi

  echo "Delete the contents of the file!!!"
```

# 改善メモ
- セキュリティの観点から作業後は自動でリストの中身を削除するようにする
- 削除用の処理も追加して、スクリプトの引数としてaddやdeleteなどを指定することで使い分けることができるようにする
メモリ圧迫テストで利用できるコンテナの作り方

インフラ環境の構築や検証をしているとメモリが圧迫された時の挙動を確認したくなる時があるかと思います。
そんな時に以下のコンテナを使うと指定したメモリを専有してくれて便利です。
（k8s環境を想定していますが、dockerさえ入っていればdocker runで起動することが可能です）

## 構成
・docker-entrypoint.sh
・Dockerfile
・deployment.yml

## 内容

・docker-entrypoint.sh

```
#!/bin/sh

MEMORY_USE_M=`echo $(($MEMORY_USE/1024/1024))`

echo "${MEMORY_USE_M}MB"
/usr/bin/stress -m 1 --vm-bytes $MEMORY_USE --vm-hang 0 -q
```

・Dockerfile

```
FROM ubuntu:18.04

ENV MEMORY_USE 1134217728

RUN curl -O http://ports.ubuntu.com/pool/universe/s/stress/stress_1.0.4-2_arm64.deb && \
    apt-get install ./stress_1.0.4-2_arm64.deb
ADD docker-entrypoint.sh .

ENTRYPOINT ["sh", "./docker-entrypoint.sh"]
```

・stress.yaml

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: stress
  labels:
    run: stress
spec:
  replicas: 1
  selector:
    matchLabels:
      run: stress
  template:
    metadata:
      labels:
        run: stress
    spec:
      containers:
      - image: stress:latest
        name: stress
        imagePullPolicy: IfNotPresent
        env:
        - name: MEMORY_USE
          value: "2134217728"
```
Sourcetree で GitHub に ssh 接続する[Windows]

# やること

Sourcetree では ppk 形式の鍵しか読み込めず、GitHub では OpenSSH 形式の鍵しか読み込めない。
そして、PuTTY Key Generator は OpenSSH の鍵を読み取ってくれない。

なので、既存の OpenSSH 形式の秘密鍵を使うことはあきらめて（作成済みであれば）、PuTTY Key Generator で ppk 形式の鍵を新規に作成。
そこで同時に作成される OpenSSH 形式の公開鍵を GitHub の方に登録してあげる。

# 鍵の作成

Sourcetree 起動 > 上部メニュー > ツール > ssh キーの作成 / インポート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252342/2b673e22-ba94-71b0-61e7-502bea091e9d.png)

**generate** でキーペアを作成する。

## ppk 鍵の保存

**Save public key** **Save private key** で鍵を保存する。
(自分は **id_ppk.ppk** と **id_ppk.pub** とした .pub の方の名前がこれで良いのかちょっと不安)

## OpenSSH 形式公開鍵の取得

**Key fingerprint** だったりが書いてある上のオレンジ(?)の部分に OpenSSH 形式の公開鍵が出るので、これをファイルに保存するなりメモするなりしておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252342/9f63fc21-4a7b-2965-2265-3dd56245b7c1.png)

# 鍵を GitHUb に登録

https://github.com/settings/keys で **New SSH Key** を選択し、さっき保存した **OpenSSH 形式の公開鍵** を追加する。

# 鍵の読み込み

 Pagent (画像左上の青いの) を右クリックして **Add Key**、保存した ppk の秘密鍵を読み込ませる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252342/eace4090-0b4b-c001-d339-49e035216f59.png)

# これで大丈夫なはず

Sourcetree を開いて ssh での Fetch 等が正常に実行できるようになっているはず。
gitのプロジェクトを爆速でSourceTreeで開く方法

**SourceTreeにブックマークされていないgitプロジェクトをSourceTreeで開く**ためには手動で以下の手順を踏む必要があり**とても面倒くさい**と感じています。

1. SourceTreeを起動させる
2. ブックマークを表示させる
3. gitプロジェクトをブックマークにD&Dする

しかし、**SourceTreeのコマンドラインツール**をインストールすることで**爆速化**させることが可能です。

## SourceTreeコマンドラインツールのインストール

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/f34a8688-3cd7-80c9-c178-8959490908c8.png" width =250 />
`SourceTree > コマンドラインツールをインストール`をクリックします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/fa5c4b60-49e3-a420-ddb9-95e133f56f00.png" width=350 />
1秒かからずインストールが完了し、**stree**というコマンドが使えるようになります。



## streeコマンドでSourceTreeを開く

SourceTreeで開きたいプロジェクトのパスを指定して**streeコマンド**を実行します。

```shell
$ stree SourceTreeで開きたいプロジェクトのパス
```

すると指定したプロジェクトを開いた状態でSourceTreeが開きます。
※SourceTreeが起動していなければ、**起動後にプロジェクトを開いてくれます。**

## SourceTree管理外の場合はブックマーク登録可

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/df74f9f4-8487-9978-16dd-f507d93c6fdd.png" width=500 />

SourceTree管理外(ブックマーク未登録)の場合は、上記のようなダイアログが表示され、そのままブックマークに登録できます。

## 最後に

**日常的にコマンドラインを使い、gitはSourceTreeを採用しているエンジニア**は**ノーリスク**で爆速を手に入れられるので必ずインストールしておくべきツールだと思います。

## 環境

Mac版 SourceTree 4.0.1
IBM Cloudの利用を始めるときに何はともあれやるべきこと

IBM社が提供しているクラウドサービスである「IBM Cloud」。
このIBM Cloudの利用を始めた際、まず最初に実施すべきことはアカウントのセキュリティの設定です。

他のクラウドサービスにおいても同様ですが、パブリックなクラウドサービスを利用していて最も怖いことは、意図しない高額の請求です。
自分のアカウントを第三者に不正利用され、クラウドサービスの資源を大量に使用された結果、クラウド事業者から多額の請求がくるというものです。

[APIキーのGitHubでの流出](https://qiita.com/mochizukikotaro/items/a0e98ff0063a77e7b694)など、うっかりミスが原因のものもありますが、アカウント自体のセキュリティもきちんと確保しておく必要があります。

パスワードを強固なものにしておくというのは基本中の基本ですが、それに加えて必ず設定すべきなのは「多要素認証」です。

IBM Cloudでは、スマホアプリの「Google Authenticator」、「IBM Verify」を利用したワンタイムパスワードによる多要素認証をサポートしていますので、アカウントを作成したら、まずはこれを設定しておきましょう。

手順は以下の通りです。

IBM Cloudにログイン後、画面右上のユーザアイコンをクリックし、「プロファイルと設定」を選択します。
<img width="200" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386149/73fe7a93-a9fd-2d93-6562-3a7ec4ebc292.png">

画面左の「ログイン設定」をクリックし、表示された画面で「時間ベースのワンタイム・パスコード認証」の「セットアップ」ボタンを押下します。
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386149/10049d86-3c70-e905-6119-591e9973ae1c.png">

すると、ダイアログでQRコードが表示されますので、そのQRコードをGoogle Authenticator、または、IBM Verifyでスキャンし、「OK」ボタンを押下します。

そうすると、以下のようにワンタイムパスワードが有効になった旨のメッセージが表示されます。
<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386149/f7e78077-02a1-8126-dcaa-d010051258f5.png">


これ以降、ログアウトしたうえで再度ログインすると、ワンタイムパスワードが要求されるようになります。

その際は、Google Authenticator、または、IBM Verifyで表示されるパスコードを入力すればログインできます。


※上記の手順で、ダイアログでQRコードが表示され、ダイアログの「OK」ボタンを押下することでワンタイムパスワードの認証が有効になりますが、現時点(2020年8月1日)では、有効になる前にワンタイムパスワードの入力・検証が求められず、次回のログイン時に初めて入力が求められました。そのため、**QRコードが表示されたもののGoogle Authenticatorなどでのスキャン・アプリへの登録を実施せずに進めてしまうと、ログアウト後、再度ログインができなくなります**。ご注意ください。
【Laravel】定義した「名前付きルート」からのURL生成方法

## 名前付きルートへのURLを生成するには

ルート定義ファイル`routes/web.php`に名前付きルートの設定をしていれば、その名前をグローバルな`route`関数を使用することで、URLを生成したり、設定した名前のルートへリダイレクトできたりします。

```php:例
// URLの生成
$url = route('profile');

// リダイレクトの生成
return redirect()->route('profile');
```
上記のように、コントローラ内とかで利用可能です。
ルート定義で名前付きルートをするだけで、リダイレクトの文が、とても見やすくなります。ぜひ活用してみましょう。

## パラメータも付け加えて、URLを生成することもできる

ちなみに、名前付きルートを設定したルートで、なおかつ、パラメータも定義してある場合は、`route`関数の第2引数にパラメータを渡すことができます。

```php:routes/web.php
Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');
```
上記のように、ルート定義で`profile`という名前を指定のルートにつけて

```php:HogeController.php
$url = route('profile', ['id' => 1]);
// $urlには「 /user/1/profile 」
```
コントローラでパラメータを渡してあげて、URLを生成することができます。


参考文献：https://readouble.com/laravel/7.x/ja/routing.html
screen のカレントディレクトリをココに変更する

# screen のカレントディレクトリは chdir で変更する

[GNU Screen](https://www.gnu.org/software/screen/) にはカレントディレクトリがあり、新しいウィンドウを作成した時の初期ディレクトリとして使用されます。`screen` のカレントディレクトリは [chdir コマンド](https://www.gnu.org/software/screen/manual/html_node/Chdir.html) で変更できます。

```
:chdir /path/to/dir
```

# pwd の結果を chdir に指定することが多い

`screen` を日常的に使うようになってから [chdir コマンド](https://www.gnu.org/software/screen/manual/html_node/Chdir.html) を使うことが増えました。ただし、`pwd` の結果を `chdir` に指定することがほとんどです。以下の手順でおこなっていたのですが、頻繁にやるには面倒です。

 1. `pwd` でカレントディレクトリを表示する
 2. [screen でコピーする](https://www.gnu.org/software/screen/manual/html_node/Copy.html#Copy)
 3. `chdir` まで打つ
 4. [screen でペーストする](https://www.gnu.org/software/screen/manual/html_node/Paste.html#Paste)
 5. Enter キーを押す

# screen.chdir という関数にまとめた

ということで、上記を行う関数を作成しました。これを `.bashrc` などに書いておきます。

```bash:.bashrc
function screen.chdir
{
    if [[ "${STY:-}" == '' ]]; then
        echo "Not in screen." >&2
    else
        declare -r target="${1:-$(pwd)}"
        screen -S "${STY}" -X chdir "${target}"
    fi
}
```

シェルで次のように呼び出すだけで、`pwd` の結果を screen のカレントディレクトリに設定できるようになりました。

```bash
$ screen.chdir
```

# screen.chdir の解説

`screen` の `-S` と `-X` オプションを用いることで、実行中のセッションにコマンドを送ることができます。

```bash
$ screen -S SESSION_NAME -X COMMAND
```

環境変数 `STY` でソケット名を取得できるので、その値を `-S` に指定します。

これらを組み合わせることで screen.chdir を実装しました。
windows で npm i に失敗する

# やりたいこと

`npm i`

# エラー

```
npm ERR! cb.apply is not a function

npm ERR! A complete log of this run can be found in:
```

# 解決法

nodejs のインストールに nodist を使っていたが、node を直接インストールして実行するように変更すると動くようになった。

## 実行したコマンド

```powershell
# nodist のアンインストール
> choco uninstall nodist
# node を直接インストール
> choco install -y nodejs.install

# shell を開きなおす
> node -v
v14.7.0
> npm -v
6.14.7
> npm i -g npm
+ npm@6.14.7
added 434 packages from 880 contributors in 6.276s
>
```
【Vuetify】v-comboboxをアクティブ状態で送信ボタン押すと以前の値が取得される問題

**再現手順**
①v-comboboxで手入力する
②v-comboboxをアクティブ状態のまま送信ボタン押下
→以前の入力データが取得されてしまう

**問題のコード**
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="html,result" data-user="xigns" data-slug-hash="WNrVJZv" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="v-combobox input issue">
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

上記でコンボボックスに何か入力（項目選択ではない）してアクティブ状態のまま送信ボタンを押してみてください
アラートに何も表示されませんが、2回目送信ボタンを押すと表示されます。

```vue:.vue
<div id="app">
  <v-app>
   <v-combobox
               v-model="userValue"
               :items="userItems"
               ref="userComboBox"
               >
     </v-combobox>
    <v-btn color="primary" dark large @click="submit()">送信</v-btn>
  </v-app>
</div>
```

```js:.js
new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data () {
    return {
      userValue: "",
      userItems: [
        "A","B","C"
      ],
    }
  },
  methods:{
    submit(){
      alert(this.userValue);
    }
  },
})
```
submit関数内のconsole.logで出力されるデータは現在入力されているデータではなく、
以前のデータが取得されてしまう。
v-comboboxは非アクティブにならないと入力情報がv-modelに伝わらない。
v-text-fieldではこの現象はもちろん発生しない。v-modelへの反映は入力されたら即時行われる為。



**解決法はコンボボックスを非アクティブ(blur)してnextTickを使用する**

```js:.js
 submit(){
      this.$refs.userComboBox.blur();
       this.$nextTick(() => {
         console.log(this.userValue);
       })
    }
```
golangでOpenLDAPサーバへ接続する

# サーバを立てる

- DockerでOpenLdapを389で起動します

https://qiita.com/yuta_vamdemic/items/53cd67eea5af71ffd08a

# 認証する

### Ldapモジュールをインストール

```bash

go get github.com/go-ldap/ldap
```

### コード

```golang

package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/go-ldap/ldap"
)

func ExampleconnSearch() (bool, error) {

	ldapServer   := "ldap://localhost:389"
	err := errors.New("connection error")

	// ldapServerへの接続確認
	l, err := ldap.DialURL(ldapServer, ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: true}))
	// 接続失敗時のエラーハンドリング
	if err != nil {
		fmt.Printf("%s\n", "ldap connection error")
		return false, err
	}

	fmt.Printf("%s\n", "ldap connection success")
	defer l.Close()
	return true, nil
}

func main() {
	ExampleconnSearch()
}

```

### 実行結果

```
$ go run main.go
ldap connection success
```