OmniAICreator/Qiita-1.07M huggingface dataset:
Symbolノードの接続関係を表示するnem2-peers-graphつくった

# はじめに

カタパルトのRESTに`/node/peers`というエンドポイントができて、対応するAPIノードが他のどんなノードと接続しているのかがわかるようになった。

本家githubのv0.7.20にはそれが見つけられないが、

https://github.com/nemtech/catapult-rest/blob/v0.7.20/rest/src/routes/nodeRoutes.js

こちらにはあった

https://github.com/Alexhuszagh/catapult-rest/blob/02fea32d60b901001e2cdef2e18fd6b62c3e5725/rest/src/routes/nodeRoutes.js

RESTは基本的にはmongoDBの情報を参照している。しかし、APIノードが接続している他ノードの情報は、mongoDBに書かれているとは思えない。

なのでこれは、ノードのがそういう機能を持っていて、RESTは直接ノードに問い合わせていると思った。

もしそうならば、APIノードでもPeerノードでも、接続しているノードの情報が取れるのではないか。

それが取れたら、ノード間の接続図なんかも作れそうだ。

# 作った

https://tools48gh23s.z31.web.core.windows.net/peers-graph/index.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/31d8bbfd-25dd-b168-041b-2ca006d74e8d.png)

# ノードの接続先情報を取得する

catapult-sdkを使う。catapult-sdkとは、catapult-restに同梱されているNodejsで作られたライブラリで、APIノードやPeerノードと直接やりとりすることができる。

これ単体ではnpmなどにパブリッシュされていないので、プロジェクト内に手動でコピーして利用する。

[catapult-sdkの使い方はこちら](https://qiita.com/planethouki/items/85691e42b8a819043adc)

ここに、`nodeDiscoveryPullPeers`といういかにも、なワードがあるので、これを利用する。

https://github.com/Alexhuszagh/catapult-rest/blob/02fea32d60b901001e2cdef2e18fd6b62c3e5725/catapult-sdk/src/packet/PacketType.js#L52

できあがったのがこちら

https://github.com/planethouki/nem2-peers-graph/blob/master/discover/NodePeers.js

# できるだけ多くのノードから情報を取得したい

ノードの他ノード接続一覧が取得できるのだから、そこから芋づる式に情報を取得していけばよい。

再帰を使って、こんな感じになりました。

https://github.com/planethouki/nem2-peers-graph/blob/master/discover/fetchPeers.js

# グラフを作る

[vis.js](https://visjs.org/)というのを使った。

[ドキュメント](https://visjs.github.io/vis-network/docs/network/)によれば、

```javascript
    var nodes = new vis.DataSet([
        {id: 1, label: 'Node 1'},
        {id: 2, label: 'Node 2'},
        {id: 3, label: 'Node 3'},
        {id: 4, label: 'Node 4'},
        {id: 5, label: 'Node 5'}
    ]);

    // create an array with edges
    var edges = new vis.DataSet([
        {from: 1, to: 3},
        {from: 1, to: 2},
        {from: 2, to: 4},
        {from: 2, to: 5}
    ]);
```
こんなデータを作って、

```javascript
var network = new vis.Network(container, data, options);
```

こうすればいいらしい。

出来上がったのが、こちら

https://github.com/planethouki/nem2-peers-graph/blob/master/discover/generateVisData.js


# ノード一覧を作る

併せて、テーブル形式でノード一覧を表示したい。

テーブル表示ライブラリには、[Tabulator](http://tabulator.info/)を使った。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/461cf3de-2d51-f051-0dc6-160899beaa41.png)

## 地理情報を表示

ノードのIPから、地理情報を取得する。

これは、[IP-API.com](https://ip-api.com/)を使った。

次に、これをマップで表示したい。

[amCharts](https://www.amcharts.com/)を使った。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/1ac9f143-116e-329b-a1df-6af1eda9f076.png)

いい感じ。

# その他

あとは、どのマシンで動かすか。

- ノードの情報を取得するプログラム
- vis.js用にデータを整形するプログラム
- 地理情報を取得するプログラム
- マップにデータを整形するプログラム

これらは、Azure Functionsで定期実行することにした。

Webサイトは、すべて静的とし、Azure BLOB Storageに配置した。

# おわりに

こういうのは、すでに、いろんな人が、いろんなものを作っているので、特に目新しいわけではないけれど、作ってみたので、記事にしてみた。
ナレッジグラフ"STARDOG" Platform install for Ubuntu

# 1.STSRDOGとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10574/84ae9a05-f5b5-ddcc-eee8-c81333efecaf.png)

STARDOGとはアメリカの企業で、主力ソリューションにナレッジグラフの統合データ環境Platform「STARDOG」と操作環境「STSRDOG STUDIO」があります。
競合にスゥエーデンNeo Technology社のneo4jが挙げられまして、日本語に翻訳されているのは後者、neo4jの方が有名でしょう。

# 2.ナレッジグラフとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10574/4d927cd3-2d6d-b0fb-ec31-a753d9cedcc1.png)

https://www.gartner.com/jp/newsroom/press-releases/pr-20190830
ガートナーの先進テクノロジのハイプ・サイクルに2018年初登場、2019年も登場しており「過度な期待」ゾーンにあと一歩と迫るナレッジグラフ。

ナレッジグラフ自体は「パナマ文章」の解読・可視化にneo4jが使われたことで一気にその知名度を挙げました。グラフDBという呼び方もありますが、同義です。

[title](https://medium.com/@c_z/%E3%83%91%E3%83%8A%E3%83%9E%E6%96%87%E6%9B%B8-%E8%A7%A3%E6%9E%90%E3%81%AE%E6%8A%80%E8%A1%93%E7%9A%84%E5%81%B4%E9%9D%A2-d10201bbe195)


# 3. ナレッジグラフが脚光を浴びた「パナマ文章」
しかし、今回のデータにはおよそ215,000もの会社（おそらく多くがペーパーカンパニー）が含まれており、そこを流れるカネを分析するためにはもう一工夫が必要です。ある会社の会計報告や登記簿を読んでいる場合、その会社の関係者、そしてその会社に関連する他の企業などのつながりを見られるようになれば、カネの流れを把握するのに大いに役立ちます。もちろんこれは文章でも表現できます。

パナマ文章はこうして膨大なデータを解析することで紐解きされました。

以下のような情報を得たとします:

1.A社の現在の社長はx氏
2.A社はB社の取締役であるY氏によって設立された
3.Y氏は『A社』というキーワードが大量にヒットするメールをZ氏に頻繁に送っている
4.αという住所にA社があり、B社の所在地はβである
5.αとβはグランドケイマン島の、γビル内の同じフロアに存在する
6.Z氏はγビルのオーナーである

上記情報から以下の推論を導き出す事ができると、上記サイトでは言っている。

X氏とY氏にはA社の創業者とその後継者という繋がりがあり、B社はA社と何らかの繋がりがある。そして会社の登記には名前がないが、Z氏とA社にはY氏を介しておそらく何らかの関係性が存在する。そして両社の所在地から、これらは同一ブローカーが関与して設立されたペーパーカンパニーの可能性がある。そのブローカーはZ氏の可能性がある。

 この推論を数十万、数百万の組み合わせで人が把握するのは不可能であり、そのためにグラフDB、ナレッジグラフが登場します。 

# 4.neo4jSTARDOGのインストール
さて今日は「STARDOG」のPlatformのインストール方法です。Mac OSのインストール事例を参考にしながら、我が家のポンコツ開発機Ubuntuに合わせて手順を変えていきます。

## 4-1.Java8のインストール確認
STARDOGはJAVA上で実行されます。自分の環境にJAVA8以上が入っているか確認が必要です。

``` java:version.java
$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1ubuntu1~18.04.1-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)  
```

## 4-2.STARDOGからPlatformをダウンロード
![20200202164012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10574/6cd35d36-ceed-0afa-f066-93a08eb57f33.png)


https://www.stardog.com/get-started/
正直dockerが一番良いと思いつつ、我が家のポンコツはdocker動かすとCPUファンの回転数が上がるので、パッケージを素直に「Download」タブからダウンロード。

## 4-3.unzip
``` sh:4-3.sh
# unzip stardog-latest.zip
``` 
この記事を執筆している時点では、stardog-7.1.1ディレクトリが出来上がります。

## 4-4.Platformの起動
``` sh:4-4.sh
# cd stardog-7.1.1
# stardog-admin server start (これでは起動しない）
#./stardog-admin server start
``` 


## 4-5.DatabaseのCreate
/stardog-7.1.1/bin# ./stardog-admin db create -n BreadDB

Successfully created database 'BreadDB'.

どうやら成功。

## 4-6.status確認
/stardog/stardog-7.1.1/bin#./stardog-admin server status
![20200202171247.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10574/bb7c66bf-155b-81f4-5316-9051302380b1.png)
作成したDBがDataBasesに表示されているのでOK。

## 4-7.STARDOG PlatformのSTOP
こまめにSTOPして、マシンリソースを節約しましょう。

/stardog/stardog-7.1.1/bin# ./stardog-admin server stop
Stardog server successfully received the shutdown request.

 以上。次回はSTARDOG stadioのインストールします。
VBScriptでプロキシの設定を切り替える

# 概要

VBScriptでプロキシの設定を切り替えます。

インターネットオプションのレジストリ(システムのプロキシ設定)を書き換えて実現します。

この方法は、たとえば、即座にブラウザに反映させたい場合には不向きです。(ブラウザの再起動が必要になる)
そのようなケースは各ブラウザの拡張機能を利用するのがよいと思います。

# 要点

`HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable`
でプロキシサーバを利用するにチェックを入れて

`HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer`
にプロキシサーバのアドレスとポートを設定すればOKです。

```vb
' レジストリ
Const REGKEY_PROXY_ENABLE = "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable"

Const REGKEY_PROXY_SERVER = "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer"

'プロキシサーバを利用するにチェック
objShell.RegWrite REGKEY_PROXY_ENABLE, 1, "REG_DWORD"
    
'プロキシサーバのアドレスとポートを設定
objShell.RegWrite REGKEY_PROXY_SERVER, "localhost:3128", "REG_SZ"
```

プロキシを解除するときは、
`HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable`
でプロキシサーバを利用するのチェックを外すだけでOKです。


# ソース

プロキシ設定用の簡単な画面をつけています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34777/f163b8b9-9220-19c7-2906-d0d08aceea48.png)

```html:proxy.hta
<!DOCTYPE html>
<html>
<head>
    <title>Proxy</title>
</head>
<script language="vbscript">
' 画面サイズ変更
Sub Window_OnLoad
  Window.ResizeTo 240,120
End Sub
</script>

<body>
	<input type="radio" name="proxy" value="proxy1" onclick="SetProxy()">プロキシ設定<br>
	<input type="radio" name="proxy" value="proxyNone" onclick="RemoveProxy()">プロキシなし<br>
</body>

<script language="vbscript">

' レジストリ
Const REGKEY_PROXY_ENABLE = "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable"

Const REGKEY_PROXY_SERVER = "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer"

' オブジェクト
Dim objShell:Set objShell = CreateObject("WScript.Shell")

' プロキシ設定
Sub SetProxy()
  'プロキシサーバを利用するにチェック
  objShell.RegWrite REGKEY_PROXY_ENABLE, 1, "REG_DWORD"
    
  'プロキシサーバのアドレスとポートを設定
  objShell.RegWrite REGKEY_PROXY_SERVER, "localhost:3128", "REG_SZ"

  If objShell.RegRead(REGKEY_PROXY_ENABLE) = 1 Then
    server = objShell.RegRead(REGKEY_PROXY_SERVER)
    MsgBox("プロキシ設定成功:" & server)
  Else
    server = objShell.RegRead(REGKEY_PROXY_SERVER)
    MsgBox("プロキシ設定失敗:" & server)
  End If
End Sub


' プロキシ解除
Sub RemoveProxy()
  ' プロキシサーバを利用するのチェックを外す
  objShell.RegWrite REGKEY_PROXY_ENABLE, 0, "REG_DWORD"

  ' プロキシサーバのアドレスとポートに値が入っていても
  ' プロキシは解除されているので、以下はコメントアウトしておく
  ' objShell.RegWrite REGKEY_PROXY_SERVER, "", "REG_SZ"

  If objShell.RegRead(REGKEY_PROXY_ENABLE) = 0 Then
    MsgBox("プロキシ解除成功")
  Else
    MsgBox("プロキシ解除失敗")
  End If
End Sub

</script>
</html>

```
【online】Salesforce 知识分享（１）

#【前言】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/de52dfb7-eccf-2235-fa2c-1b6f97fbfedd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/9e985d06-7648-0c02-373b-ee396917569b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/3a6ce9f2-0992-6c6f-16c1-3b36640f1d05.png)

#【分享内容】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/19e412dc-9d77-12fe-3f63-d6634f03c858.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/71d88e58-2c05-f20d-c7e5-dfa4221ed4d0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/22cd5853-2314-4583-d53f-95542daa9ec4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/90e9416f-c1b5-e381-ea72-818fa42bbac8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/0f2242e2-6efb-c8c3-4c23-8dc252b21fa7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/f67325b9-7342-219a-5897-38fcd53926f9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/ba7d4a88-1397-9d93-eb49-a38d88d4567e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/658eb6fb-9fe9-24c3-8cbd-1cd4ce6a4714.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/8ae74df2-c30c-954f-e8cf-4a9efc946979.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/58b71cd3-3dc5-acc6-d86f-f0d3d29229fe.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/39789ae9-e3c6-4fae-1e7e-405b4b3d477e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/39e981ad-2981-02d6-79d8-1ec81b78134b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/9c49b134-911c-f2ab-6190-a4649a3c2e60.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/f2ef5e11-fbcc-3b83-af6d-7fac47726234.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/47ba4685-0618-b38a-3cf3-fb45478a4d0e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/e486fcdc-f3fd-a42f-3e79-b876aad42b3a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/1ce4ff5c-6cc5-a74f-2579-1688c6ae5ba2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/9329bdf4-77e3-5ee7-bd30-7b26413997a3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/9197ed81-a159-38ec-9aba-9615db4850d2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548773/64ce9ee8-5e5e-3c30-26a6-9b0f69a7cc1b.png)
headless-chrome を Debian ベースのイメージ上で動かす

# スクレイピングで js を読み込みたい
Mac os でローカルの中だけでやる分には、いまだに phantom.js が快適に動いてくれるので、ヘッドレスブラウザの利用が簡単なんだけれども
Cloud Run で使用したかったので、公式のpythonイメージで動作確認しようと思ったら、意外とややこしかったのでメモしておく

# 訳わからん情報が溢れてる
どうやら phantom.js は更新をやめてしまうということだったので、大人しく headless-chrome を使用することにしたけど
工数を使用したくなかったので、他の人達の記事を漁った
でも僕はアホなので、記事を見てもとにかくわからんかった、もう自分でなんとかすることにした

# 結論
特に難しいことはなく、以下の条件を満たせば簡単に動く

```
chrome 本体をダウンロード
chrome 本体に合ったバージョンのドライバをダウンロード
起動時のオプションを適切に設定
```

# Dockerfile
使用したベースイメージ

```
# Use the official Python image.
# https://hub.docker.com/_/python
FROM python:3.7
```
Chrome 本体のダウンロードをする、インストール時のバージョンは必ず見ておくこと

```
RUN sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN apt update
RUN apt install google-chrome-stable -y
```

Driver のダウンロードする、先にChromeのバージョンに一番近いやつを探す
https://chromedriver.storage.googleapis.com/
そんで、本体のバージョンに一番近い最新版を探す、今回は80台だったからこう
https://chromedriver.storage.googleapis.com/LATEST_RELEASE_80

見つけた番号でダウンロード＆解凍するよ

```
RUN wget https://chromedriver.storage.googleapis.com/80.0.3987.106/chromedriver_linux64.zip
RUN unzip chromedriver_linux64.zip -d /usr/bin/
```

もちろんだけど、この段階で両方ともPATHが見える様にしておくこと

```
which chromedriver
witch google-chrome
```

こんだけでOK
あとは使用するだけ、一応使用例も書いとく

```app.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup


URL = "https://example.jp"


def get_trends():
    try:
        options = Options()
        options.add_argument('--headless')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')

        driver = webdriver.Chrome(options=options)
        driver.get(URL)
        html = driver.page_source.encode('utf-8')  # more sophisticated methods may be available
        soup = BeautifulSoup(html, "lxml")
```

# 終わり
ぶっちゃけメモ
[python]関数をリストに入れて管理する

#はじめに
moduleに複数のロジックがあって、それらをある関数から呼び出したいということはあると思います。

# 参考

[こちらを読むと良いと思います！](https://amzn.to/2Blfuex)

# やり方

####構成
```
├── modules
│   └──logic.py
│ 
└─ main.py
```

####コード
```python:modules/logic.py
def func1(word):
    print('こちらfunc1' + word)
    
def func2(word):
    print('こちらfunc2' + word)   
    
def func3(word):
    print('こちらfunc3' + word) 

def func4(word):
    print('こちらfunc4' + word) 

def func5(word):
    print('こちらfunc5' + word) 
```

```python:main.py
import modules.logic as logic


def func(func_num, word):
    a = [_,
         logic.test1,
         logic.test2,
         logic.test3,
         logic.test4,
         logic.test5]
    return a[func_num](word

if __name__ == '__main__'
    func(1,'です')
    func(2,'やで')
    func(3,'だよ')
    func(4,'にょろ')
    func(5,'だじぇ')
```

####実行と結果
```
$ python main.py

こちらfunc1です
こちらfunc2やで
こちらfunc3だよ
こちらfunc4にょろ
こちらfunc5だじぇ
```

#ひとこと
もっと良い書き方ありましたら教えてください。
応用情報技術者試験　合格への道：ネットワーク:通信プロトコル

下記まとめは午前試験の過去問をざっと洗って、”過去問がもう一度出た時にちゃんととけるように”まとめたものになります。

試験まで時間がない時の勉強や、試験直前のおさらいに使いください。

#■OSI参照モデル　TCP/IP階層モデル　違い

**・OSI**　アプリケーション層、プレゼンテーション層、セッション層
　↓
**・TCP/IP**　アプリケーション層

トランスポート層は名前、区分が同じ

**・OSI**　ネットワーク層
　↓
**・TCP/IP**　インターネット層

**・OSI**　データリンク層
　↓
**・TCP/IP**　ネットワークインターフェイス層

#■SNMP(Simple Network Management Protocol)

　TCP/IPネットワーク上でネットワーク上の機器の情報を収集して、監視や制御を行うためのプロトコル。アプリケーション層。
　同じアプリケーション層のプロトコルはFTPだけ。

**・SNMPトラップ**
　SNMPエージェント(サーバA)からSNMPマネージャ(サーバX)に障害発生などのイベントの発生を通知するコマンド。

#■IPsec

IP(Internet Protocol)を拡張してセキュリティを高めたプロトコル
改ざんの検知、通信データの暗号化、送信元の認証などの機能をネットワーク層レベル(TCP/IPモデルではインターネット層)で提供する
IPsecを用いたインターネットVPNをIPsecVPNという。

#■IPv6

IPv6は、主流のIPv4にかわる通信プロトコル
ユーザ認証、パケットの暗号化をIPレイヤで行うIPsec(Security Architecture for IP)の機能がサポートされている

IPv6アドレスのアドレス長は128ビット、IPv4(32ビット)の4倍。
IPv4：32ビットを8ビットごとに区切り、それぞれを10進数で表したものを"."で連結
IPv6では128ビットを16ビットごとに区切り、それぞれを16進数で表したものを":"で連結

以下の2つの規則に従った短縮表記が可能

各16ビットセクションの先行する 0 を省略する。例えば、0012 は 12 になる。ただし、16ビットセクションが 0000 のときは 0 とする。
0 の16ビットセクションが連続する場合は、連続する2個のコロン(::)で表す。

　2001:0db8:0000:0000:0000:ff00:0042:8329
　↓
　2001:db8::ff00:42:8329

　と表す。ただし、:: は1か所にだけ使用できる。

#■PPP

ダイヤルアップ接続で使われていた接続形式。2点間を接続してデータ通信を行うための通信プロトコル。
通信制御にリンク制御プロトコルとネットワーク制御プロトコルが使用されている
エラー処理機能をもち、認証プロトコルや圧縮プロトコルが規定されている。

#■SOAP(ソープ，Simple Object Access Protocol)

ソフトウェア同士がメッセージを交換する遠隔手続き呼び出し(RPC)のためのプロトコル。
XMLに基づいて記述されている。
　
ソフトウェアが商品データを要求するときにXML形式であるSOAPリクエストを発行し、それに対してWebサービス側からも要求に基づいて商品データがSOAPメッセージとして戻るという仕組みです。

#■REST(Representational State Transfer)

HTTPのGETメソッドをリクエストを送信するとXML形式のデータが返ってくる。
ECサイトなどで指定されたURLに対して要求したいサービスを示すパラメータを指定したリクエストを送ると、商品情報などが含まれるXMLデータを取得することができる。

#■TCP

TCP/IPネットワークにおいて通信を行う2つのノード間にコネクションと呼ばれる論理的な通信路を確立し、送達管理や伝送管理などの機能を提供するプロトコル。

パケットの宛先となるアプリケーションを指定する情報がポート番号。

ウィンドウサイズは、TCP通信において受信側が現在受信可能なデータサイズを送信側に伝えるために使用されるTCPヘッダ内のフィールド。　　

#■UDP

TCPと異なりコネクションレス型の通信。途中でデータが抜け落ちても問題が少ない音声や画像のストリーム形式での配信などで使用される。

トランスポート層に属する

#■ブロードキャスト

ホストアドレス部の全ビットを「1」に設定することでブロードキャストが実行できる仕組み。
面倒くさがらずにちゃんとビットを書かないと間違えます。
最後が255、ってなっていもサブネット次第だとブロードキャストアドレスじゃないこともあります。

##・ブロードキャストフレームとブロードキャストストームの違い

**ブロードキャストフレーム**
　→宛先MACアドレスがFF-FF-FF-FF-FF-FFで送信され，LANに接続した全てのPCが受信してしまうこと

**ブロードキャストストーム**
　→ループ状に接続されているネットワークにおいて、同一のブロードキャストフレームが増幅しながら永遠にネットワーク内を回り続けること

#■IEEE802.1x

LANにおけるユーザ認証の規格で、正当な端末以外がLANに参加することを防ぐ技術
「サプリカント(端末)」、RADIUSなどの「認証サーバ」、RADIUSクライアントの機能を持ち、認証サーバ間の認証プロセスを相互に中継する認証装置である「オーセンティケータ」の3つの要素で構成される。

#■ICMP(Internet Control Message Protocol)

通信制御を補完するプロトコルで、データ配送中のエラー通知や送達エラーを通知する機能を持つ。
pingは、ICMPのプロトコルを使用して接続状態を調べている

ネットワーク層に属する

#■ホストアドレスを求める式

IPv4ネットワークで使用されるIPアドレス a とサブネットマスク m からホストアドレスを求める式

a＆～m

サブネットマスクのマスクを反転させてANDをかければ、ホストアドレスだけ有効になる

#■VRRP(Virtual Router Redundancy Protocol)

ルータやL3スイッチの冗長構成を実現するプロトコル。

複数台のルータに共通して使える仮想IPアドレス・仮想MACアドレスを用意し、障害発生時には2つのアドレスをフェールオーバで待機系に移すことで継ぎ目なく処理を続行する。
ホストのデフォルトゲートウェイの設定値などを変更することなしに、送信先の装置を正常稼働するものに置き換えることが可能になる。


#■まとめ

そろそろ他の項目で勉強したものと重複するものが出てきます。
**・ARP**
**・RARP**
**・DHCP**
**・DNS**
**・サブネットマスク**
**・IPネットワークの集約**
関連は他の項目で説明済みなので今回は触れていません。

量が多いのでかなりの駆け足になってしまいました。

次回は**「ネットワーク管理、ネットワーク応用」**を予定しています。

ネットワークに関しては最終回になります！
ユーザ情報をどうDB設計するか突き詰めて考えてみる

# この記事について
- システム開発するうえで絶対に避けては通れないユーザ情報周りの設計を自分なりに考察してみた
- 結局何が最適かわからないけど色々と考え出すと奥が深かった

# きっかけ的な
[Railsでアプリ作ったんだけど](https://github.com/gitk47320/forum)、bootstrapとかdeviseとか使って横着したので、正直やった感ないなーって思いました。HTML/CSS多少勉強しなおして、あと[この本読んで](https://www.amazon.co.jp/dp/B082XXMVBK/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)、もう一回横着しないでなんちゃってQiitaみたいななんちゃってメディアシステムみたいなの作ろうかなと。そうなると、当然ユーザ情報の設計とか考えなきゃなんですが、いろいろ考えたら奥が深かったのでQiitaに載せて整理しようかなーって思いました。あと、ここに公開すればありがたいお言葉を頂戴いただけるのではないかとか思ったり。

# 本記事のユーザ情報の定義
## 利用用途
 - ログイン認証に用いる。
 - サインアップ画面より、新規登録をユーザ自身で可能とする。
 - ユーザによるプロフィール編集を可能とする。
 - プロフィールは他ユーザにより、CMS上のある画面から一覧表示できる。また、個別のユーザはユーザ名で検索可能とする。
 - プロフィール詳細はほかユーザにより、CMS上のある画面から確認可能とする。
 - ユーザ削除時は、ログイン情報も含めてすべて物理削除する

## 項目定義
 - 一意のログインID、パスワードをもつ。また、最終ログイン日時を保持する。
 - CMS内で利用される一意のユーザ名を保持する。
 - 上記ユーザ名とは別でユーザの氏名、氏名カナを保持する。ユーザの氏名、氏名カナは他ユーザは見れないものとする。
 - ユーザ登録時や運営お知らせに利用するためのメールアドレスを保持する。
 - プロフィール情報として年齢、誕生日、自由記述欄を保持する。

# 私の設計
こうなりました。詳細は追ってですが、この後簡単に思考プロセスを書いていきます。なお、簡単にするため、インデックスどうするとかは一旦考えません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127833/941e6db4-3017-f843-86a2-e00af851fb60.png)


## テーブルにどう持たせるか
まあ単純に考えるとusersテーブルにえいやって全項目突っ込みたくなりますよね。こんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239124/61356be6-f912-0ebc-b6ee-f2332d28cc30.png)
別に個人で勉強用途に使う程度ならこれでいいんですが、ある程度ユーザ増えるという前提で考えると、ユーザに関する全操作のたびにテーブルがロックされて、パフォーマンス落ちるんじゃない？とかデータ量多くなって適切にインデックス設計とかしても限界ありそうだよねとか思ったわけです。あと、このテーブルにカラム追加するとか、検索のためのタグ付けするとか、そういうの考えるとなんだか背筋が凍ります。特に住所情報持たせるとかなったらとんでもないことになりそう。

## テーブルを分けてみる
要件に立ち返ると、認証、プロフィールとあるので、この観点で分けてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127833/7bbed417-0398-bd6c-f85e-4cafce9af940.png)
ログインIDとパスワード、最終ログイン日時をauthenticatesとして定義しました。なお両テーブルは1:1で関連付けられています。
とりあえずusersテーブルのごった煮感はなくなりましたが、profileもう少しなんとかできないかなーとか思うので、もう少し分けてみます。
よく見るとほかユーザに見られてほしくない氏名の情報が混じってるのでこれは分けたほうがよさげ。と思ったのですが、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127833/329b0962-1655-6790-dc05-c47162dad2c6.png)
いい感じに分けられたんですけど、なんかセンスないというか、どう関連付けていいのかぱっと見わからないですね。。。
というわけで、fullnamesを親にして、profilesとauthenticatesと関連付けてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127833/3b9eb600-e3de-3e33-cf71-57743a004754.png)
なんかいい感じに見えました。でも親にfullnameってのがなんかあれですね。もう分けてしまいましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127833/db2873be-c813-47a8-bddc-4c95a753ddbc.png)
いい感じになったけど、なんかこれでいいのか感があります。ちょっと大げさに分けすぎてしまったかな。。。
なんかもやっとしてますけど、これで終わりにします。名前のセンスないなとかそういうのはありますが。。。

# 最後に
もやっとした感じで終わってしまったので、なんか不完全燃焼ですが、これはこれで結論ということで。
authenticatesとusersの関連付けっているのかな。正直model側でdestroyの依存をかけてしまうだけでいい気もする。でも、直接SQLで触られたりすると一気にデータがおかしくなる。。。
あと、Railsの規約って観点でもどうなのかなとも少し思ったりもした。
VSCodeで改行に置換する

csvを扱っていると、特定の文字を一括で改行に置き換えたい時があります。
このようにすると一括で置換できます。

1. VSCodeの置換機能を使う。（⌥⌘F）
2. 正規表現を使用する。（⌥⌘R）
3. 検索文字列を指定し、置換後の値には`/r`を入力する。
4. 全て置換する。（⌘Enter）
Kotlin入門:制御構文

間違いがあれば指摘していただけると幸いです。
Kotlinを簡単に実行するには[こちら](https://kotlinlang.org)
実際に打ち込んで検証するとより理解度が深まります。

実際に読んでみて良かった書籍について情報を発信していますので、
よろしければ[Twitter](https://twitter.com/KaoruTojo_Novel)のフォローもお願いします。

##if命令
構文（else ifやelseは任意）

```Kotlin
if(条件式){
    処理
}else if(条件式){
    処理
}else{
    処理
}
```

Kotlinのifは文ではなく式なので値を返せます。

```Kotlin
fun main() {
    var num = 100
    var msg = if(num == 100){
        "変数numは100である"
    }else if(num == 111){
        "変数numは111である"
①  }else{
        "変数numは100でも111でもない"
    }
    println(msg)
}
```

実行結果は

```Kotlin
変数numは100である
```
となります。

①if式では必ず値を返さなければならないため、elseを省略することはできません。

elseを省略するとこのようなエラーが発生します。

```Kotlin
'if' must have both main and 'else' branches if used as an expression
```

##when...else命令
構文

```Kotlin
when(条件となる値){
    条件となる値 ->{
        処理
    }
    else ->{
        処理
    }
}
```

式の値に応じて処理を分岐します。

```Kotlin
fun main() {
    val point = 2
    when(point){
        1 ->{
            println(1)
        }
        2 ->{
            println(2)
        }
        else ->{
            println("else")
        }
    }
}
```
実行結果は以下の通りです。

```
2
```

###条件となる値には複数の値や範囲値も指定可能

(,)カンマで複数の値を列挙したり、「in m...n」で範囲値を渡すこともできる。

```Kotlin
fun main() {
    val point = 95
    when(point){
        100 ->{
            println(100)
        }
        99,98 ->{
            println("99または98")
        }
①      in 90..97 ->{
            println("90から97の範囲")
        }
        else ->{
            println("else")
        }
    }
}
```
①の範囲値については後述します。
実行結果は以下の通りです。

```
90から97の範囲
```

###is演算子

is演算子を使用すると値ではなく型で判定することができます。

```Kotlin
fun main() {
    val name = "山田"
    when(name){
        is String ->{
            println(name)
        }
        else ->{
            println("else")
        }
    }
}
```
実行すると結果は以下の通りになります。

```
山田
```

型判定した後の式（変数）は該当する型とみなせるため、
それぞれの型に応じたメンバーを呼び出せます。


##for命令

Kotlinのfor命令はJavaでいうところの拡張forに相当する構文が基本です。

基本となる構文

```Kotlin
    for(変数 in 配列または範囲値){
        println(変数)
    }
```

入力例

```Kotlin
fun main() {
    val list = arrayOf("山田","鈴木","田中")
    for(name in list){
        println(name)
    }
}
```
実行すると結果は以下の通りになります。

```
山田
鈴木
田中
```

##範囲値
範囲演算子(..)を使用することでm~nの範囲を表現できる。

```Kotlin
fun main() {
    val i = 5
    if(i in 1..10){
        println("1~10の範囲にある")
    }
}
```

実行すると以下の通りになります。

```
1~10の範囲にある
```
製薬企業研究者のためのVisual Studio Codeインストール方法

# はじめに

Visual Studio Codeは、Microsoft社が出しているテキストエディタで、HTMLやCSSなどいろいろな言語のソースコードの編集に使えます。
テキストエディタには他にも、Atom（GitHub）やBrackets（Adobe）などがありますが、Visual Studio Codeは、Anacondaからでもインストールできるので、Pythonを利用するためにAnacondaをインストールしている人にはおすすめです。
そんなわけで、今回はAnacondaでのVisual Studio Codeのインストール方法について説明します。
なお、Anacondaのインストール方法は、以下の記事で解説しています。

[製薬企業研究者のためのPythonインストール方法](https://qiita.com/yukiya285/items/6bc3bcef00f7d13c94f1)


# Visual Studio Codeのインストール方法

Anaconda Navigatorを起動します。
すると、以下のような画面になります。
ここで、VS Codeのところの「Install」をクリックします。

![anaconda_vscode.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517951/47c92ab1-4388-e804-6a44-2f6506b2e6ef.png)

上の画像はVisual Studio Codeがインストール済みの状態なので、「Install」ではなく「Launch」になっています。
インストールが完了したら、「Launch」でエディタを立ち上げることができます。


# まとめ

ここでは、Microsoft Visual Studio Codeのインストール方法について説明しました。
次回は、HTML・CSSの基本について解説する予定です。


# 参考資料・リンク

[HTMLとは？製薬会社の仕事でどう使う？](https://pharma-engineer.com/basic-programming/html-summary/)

[CSSとは？製薬会社の仕事でどう使う？](https://pharma-engineer.com/basic-programming/css-summary/)
【NestJS】@nestjs/configを使って環境変数を読み込む

# やりたいこと

環境変数で設定した値をNestJSアプリ内で使う。

# 環境

- [NestJS 7.5.4](https://nestjs.com/)
- [@nestjs/config 0.6.3](https://github.com/nestjs/config)

`@nestjs/config`は、内部的に`dotenv`を使っています。

ref: https://docs.nestjs.com/techniques/configuration#installation
> The @nestjs/config package internally uses dotenv.

[dotenvを使う場合の手順はこちら](https://qiita.com/luigiii/items/af083bafc01e6be5930d)。


~~両方を使ってみて、環境変数の読み込みを一箇所で管理する場合は、`dotenv`そのものを使うほうが簡便だと感じました。ここでは、備忘録のため設定手順を残しておきます。~~

# 面倒な点

- ~~環境変数を使いたい場所で`ConfigService`をinjectして`config.get`を使って読み込むのが面倒（具体例は後述）。~~
  - ドキュメントには書かれていませんが、inject をしなくても `.env` の内容を `process.env.<foo>` で呼び出せます（後述）。
- `.env` で管理するため、`env.example` を作り、`cp env.example .env`するのが、特にチーム開発では面倒。途中で項目追加をすると周知が必要等。（運用方法次第かもしれません）。

# お勧め（代替案）

個人的には、[node-config](https://github.com/lorenwest/node-config) をお勧めします。
↑の「面倒な点」が解決できます。
※「面倒な点」の 1点目は inject しなくても `process.env.<foo>` すれば良いことが分かりました。

# インストール

```
yarn add @nestjs/config

// or

npm install @nestjs/config
```

# 使い方

### まず`src/app.module.ts`で読みこみます。

```typescript:src/app.module.ts
import { ConfigModule } from '@nestjs/config' // この行と
:
@Module({
  imports: [ConfigModule.forRoot()],          // この行を追加
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

global moduleとして読み込む場合は、`{ isGlobal: true }`を渡します。

```typescript:src/app.module.ts
  imports: [ConfigModule.forRoot({
    isGlobal: true,
    envFilePath: [`.env.${process.env.NODE_ENV}`, `.env`],
    load: [],
  })
```

### 実際に環境変数を使いたい場所で`ConfigService`をinjectして`config.get`を使って読み込みます

ref: https://docs.nestjs.com/techniques/configuration#using-the-configservice

このDIを使う手法は、ちょっと面倒に感じます。

```typescript:src/foo/foo.service.ts
import { ConfigService } from '@nestjs/config'

@Injectable()
export class Foo {
  constructor(
    private readonly config: ConfigService,
  ) {
    const val = this.config.get('SOME_VALUE')
```

`isGlobal: true` を設定している場合は以上ですが、設定していない場合は対応する`module`でinjectします。

```typescript:src/foo/foo.module.ts
import { ConfigModule, ConfigService } from '@nestjs/config' // ここと

@Module({
  imports: [FooModule, ConfigModule],                        // ここと
  controllers: [FooController],
  providers: [FooService, FooInvoker, ConfigService],	     // ここ
```

# inject しない

上記の「このDIを使う手法は、ちょっと面倒に感じます」については、

```typescript
imports: [ConfigModule.forRoot()]
```

を定義していれば、 `.env` の内容を `process.env.<foo>` で参照可能なので、回避は可能です。
※ドキュメントにこの利用例の記載はありませんが。

# ドキュメント

https://docs.nestjs.com/techniques/configuration
Unity の遷移をButtonを用いて行う(備忘録）

## 画面遷移をボタンを用いて行えるようにする
[前回の記事](https://qiita.com/Ah_/items/dae03a35decc1bc4a299"前回の記事")においてSceneの遷移を行えるようにしたため今回はその遷移をボタンを押すことによって遷移をすることが出来るようにしたため、その際の備忘録を付けておく。
今回躓いた点はButtonのコードをアタッチした後のButton側についての設定の仕方についてである。
以下の記事を参考にして、Buttonの設定を行った。
https://qiita.com/2dgames_jp/items/b3d7d204895d67742d0c

###躓いた点
まず、ヒエラルキーで作成を行ったGameObjectのボタンをProjectのAssetsに置く。（ここで少し躓いた）
そしてヒエラルキーのボタンのInspectorから以下の画像のように設定を行う。
![button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199067/f675321c-4f81-5c1e-5583-b6dcb051a8c1.png)


コードは以下のようになっている。

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;//これを忘れないようにすること

public class next : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
     
	}
    public void OnClick()
    {
        SceneManager.LoadScene("next1");//ボタンがクリックされた際に"next1"というSceneに遷移を行う
    }
}

```

遷移先を変更することによってさまざまなSceneに遷移することが出来るようになるはずである。
LeetCode - 326. Power of Three

# 問題

[326. Power of Three](https://leetcode.com/problems/power-of-three/) - 与えられた整数が3の累乗数かどうかを判定せよ

# 解答

ループまわすのと、再帰と考えてみる

## ループ

```ruby

# @param {Integer} n
# @return {Boolean}
def is_power_of_three(n)
  if n == 1
    true
  elsif n < 3
    false
  else
    while n != 3
      if n % 3 == 0
        n = n / 3
      else
        return false
        exit
      end
    end
    true
  end
end
```
- 3 の累乗数ならば、商が 3 になるまで 3 で割りづつけても、あまりは 0 であるはず
- X の 0 乗は 1 なので `true`

## スコア

```yaml

Runtime: 64 ms, faster than 85.71% of Ruby online submissions for Power of Three.
Memory Usage: 9.2 MB, less than 100.00% of Ruby online submissions for Power of Three.
```

## 再帰

```ruby

# @param {Integer} n
# @return {Boolean}
def is_power_of_three(n, power_value = 1)
  #puts "n=#{n} power_value=#{power_value}"
  return true if n == power_value
  return false if n < power_value
  is_power_of_three(n, power_value * 3)
end
```

- これは、[LeetCodeのサイトにあった](https://leetcode.com/problems/power-of-three/discuss/514535/Ruby-recursion-3-lines) ぱっと思いつかなかったが、すばらしい解ですね
- 3 の累乗数を小さいものから作っていき、どこかで `n`と 一致すれば `n` は 3 の累乗数、通り越してしまったら累乗数ではない

## スコア

```yaml
Runtime: 92 ms, faster than 20.00% of Ruby online submissions for Power of Three.
Memory Usage: 9.3 MB, less than 100.00% of Ruby online submissions for Power of Three.
```

きれいだけど速くはないんですね

# テスト

```ruby

require 'minitest/autorun'
require '../326-power-of-three.rb'

class DoTest < Minitest::Test

  def test_1
    assert_equal true, is_power_of_three(27)
  end

  def test_2
    assert_equal false, is_power_of_three(0)
  end

  def test_3
    assert_equal true, is_power_of_three(9)
  end

  def test_4
    assert_equal false, is_power_of_three(45)
  end

  def test_5
    assert_equal true, is_power_of_three(1)
  end

  def test_6
    assert_equal false, is_power_of_three(19684)
  end

  def test_7
    assert_equal false, is_power_of_three(-3)
  end

  def test_8
    assert_equal false, is_power_of_three(6)
  end

end
```
自然言語処理の概要まとめ

## この記事について
G検定対策で自然言語処理の概要をまとめます。

## 自然言語処理とは
自然言語処理とは、人間が日常的に使用している言語をコンピュータで処理させる技術です。

#### 自然言語処理のフロー
自然言語処理の主なフローは以下のようになります。
主な技術を併せて挙げます。

1. 文書を単語などの最小単位に分ける(`形態素解析`)
2. データのクレンジングを行い、不要な文字列を取り除く
3. データをベクトルの形式に変換する(`Bag-of-Words`)
4. 単語の重要度を評価する(`TF-IDF`)


## 形態素解析
言語で意味を持つ最小単位を`形態素`と呼びます。
形態素の品詞を判定することを`形態素解析`と言います。
形態素解析のイメージはこのような形になります。また、形態素解析は様々な解析エンジンがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502127/f7e69c0a-4e0e-6cd7-4f5a-94bb78d53995.png)


https://udemy.benesse.co.jp/ai/morphological-analysis.html


## BoW(Bag-of-Words)
Bag of Wordsは`BoW`と省略されます。
~~ブレス・オブ・ザ・ワイルドではないです。~~
BoWは単語を数値に割り当て、`one-hot表現`に変換します。

例として、以下の3つの文章を形態素解析します。

```
私はリンゴが好き
私はバナナが嫌い
私はみかんが好き
```

以下のような形態素が出きます。

```
私/は/リンゴ/バナナ/みかん/が/好き/嫌い
```

8個の形態素に番号を振ります。

```
0:私 1:は 2:リンゴ 3:バナナ 4:みかん 5:が 6:好き 7:嫌い
```

それぞれの単語をone-hot表現に変換するとこのような形になります。

```
私：[1,0,0,0,0,0,0,0]
は：[0,1,0,0,0,0,0,0]
リンゴ：[0,0,1,0,0,0,0,0]
...
```

文章にごとにベクトルを足し合わせます。

```
私はリンゴが好き
[1,1,1,0,0,1,1,0]

私はバナナが嫌い
[1,1,0,1,0,1,0,1]

私はみかんが好き
[1,1,0,0,1,1,1,0]
```

## Word2Vec
BoWと同様に単語をベクトル化する手法です。
BoWとの違いは`周辺語との関連性を考慮`できる点です。

例えば、ベクトル同士の足し算/引き算を行うと、
`「王様」-「男」+「女」=「女王」`
となることは広く知られています。

Word2Vecには`CBOW`と`Skip-gram`という2つのアーキテクチャが存在します。
両者の違いとして、CBOWは`周辺単語から中心単語を予測`し、`高速に学習`することが可能です。
逆に、Skip-gramは`中心誤から周辺単語を予測`し、`高い精度の学習`が可能です。

## fasttext
名前の通り、Word2Vecをより高速にした手法を`fasttext`と呼びます。
Word2Vecとの違いとして、`Subword分割`という手法を採用しています。
Subword分割の考え方は類似している単語は関連性を高く学習する、というものです。

## ELMo
`ELMo`はLSTMを多層につなぎ合わせることで、`文脈を考慮して単語表現を獲得`します。
例えば、Bankには「銀行」と「土手」という意味があります。
ELMoは文脈によってこの意味を解釈します。

## BERT
`BRET`は`2018年`に`Google`から`Arxiv`へ論文を公開しました。
(BRETと来たらGoogleということは覚えておくと良いです)
BRETの特徴として、Attentionという機構を用いています。
また、一部の単語を`マスキング`して学習することも挙げられます。

Attentionの機構を簡潔にまとめます。

1. 検索queryに一致するkeyを牽引する
2. memoryから該当するvalueを取得する

Attentionについてはかなりざっくりした説明ですが、詳しくは[こちら](https://qiita.com/halhorn/items/c91497522be27bde17ce)の記事で紹介されています。

## XLNet
`XLNet`はBERTの改良版として発表されました。
BERTではマスキングを行うことで学習を行いましたが、実際にタスクを解く場合はマスキングを行いません。
これがノイズになってしまいます。

XLNetはこれを回避するため、自己回帰言語モデルを採用しています。
また、自己回帰言語モデルの弱点である双方向の情報を同時に扱えない点を克服するため、単語の予測順序を入れ替える手法を用いています。

## TF-IDF
TF-IDFは`頻度が少ない単語が何度も出てきた場合、その単語の重要度を上げる`という概念です。

文章において、ある単語がどのくらい出現したのか考える概念であるTFと単語の頻度の低さ(どのくらいレアであるか)を表すIDFを組み合わせた概念です。

## 参考
* https://udemy.benesse.co.jp/ai/morphological-analysis.html
* https://www.pytry3g.com/entry/2018/03/21/181514
* https://qiita.com/halhorn/items/c91497522be27bde17ce
* https://mc.ai/bert%E3%82%92%E8%B6%85%E3%81%88%E3%81%9Fxlnet%E3%81%AE%E7%B4%B9%E4%BB%8B/
* https://dev.classmethod.jp/machine-learning/yoshim_2017ad_tfidf_1-2/
* https://deeplearning.sakura.ne.jp/
【SQL】ユーザーに紐づく投稿と投稿に紐づくコメント数・イイネ数の取得

#WITH句を使って一本のSQLで実装する。
ユーザーの詳細画面遷移時にそのユーザーの投稿とその投稿に紐づくコメント数とイイね数を取得するAPIを作るためにSQL書きました、何本もSQL走らせるのよく無いよね・・と思い、調べたら WITH句という素晴らしいものがあったので使ってみました。

※ WITH句はMySQL 8系からのサポートです。

###テーブル

**投稿テーブル**
POST 
 L ID
 L TITLE
 L TEXT

**コメントテーブル**
COMMENT
 L ID
 L POST_ID
 L TEXT

**イイねテーブル**
REACTION
 L ID
 L POST_ID

```SQL
WITH GET_COUNT AS ( -- GET_COUNT テーブルを作成
	SELECT 
	post_table.id as post_id,
	COUNT( comment_table.id ) AS comment_count
	COUNT( reaction_table.id ) AS reaction_count
	FROM post -- 投稿テーブルをベースとします。
	LEFT OUTER JOIN comment_table ON comment_table.post_id = post.id -- コメントテーブルを投稿IDで束ねる
	LEFT OUTER JOIN reaction_table ON reaction_table.post_id = post.id -- イイねテーブルを投稿IDで束ねる
	WHERE post_table.user_id = 150 -- ユーザーIDを指定する
	GROUP BY -- 投稿IDで束ねる
	post.id
) SELECT 
	post_table.id,
	post_table.tittle, 
	post_table.text, 
	GET_COUNT.comment_count,
	GET_COUNT.reaction_count
    FROM post_table
    INNER JOIN GET_COUNT ON post_table.id = GET_COUNT.post_id -- 投稿テーブルと GET_COUNT テーブルを紐付ける
    LIMIT 10 -- 10件取得
    OFFSET 0 -- 0〜10件目を取得;

```
【NestJS】dotenvを使って環境変数を読み込む

# やりたいこと

環境変数で設定した値をNestJSアプリ内で使う。

# 出来ない（または推奨されていない）こと

環境（例：development, staging）毎に異なる値を設定すること。
やれば出来るかもしれませんが、`dotenv`のドキュメントでは「推奨しない」と書かれています。
https://www.npmjs.com/package/dotenv#should-i-have-multiple-env-files

この場合は、[node-config](https://www.npmjs.com/package/config)を使いましょう。

# 環境

- [NestJS 6.11.3](https://nestjs.com/)
- [dotenv 8.2.0](https://www.npmjs.com/package/dotenv)

~~NestJS用に、内部的に`dotenv`を使っている[@nestjs/config](https://github.com/nestjs/config)もありますが、`dotenv`そのものを使うほうが簡便だと思っています。~~

[@nestjs/configを使う場合の手順はこちら。](https://qiita.com/luigiii/items/e76adcc3a65364f98537)

# インストール

```
yarn add dotenv

// or

npm install dotenv
```

# 設定

ここでは、アプリ内で統一して環境変数を読み込む場所として、`src/config/app.config.ts`を想定しています。

```typescript:src/config/app.config.ts
require('dotenv').config()

if (!process.env.DB_PASSWORD) {
  throw new Error('DB_PASSWORD must be set.')
}

export const DB_PASSWORD = process.env.DB_PASSWORD
```
Railsチュートリアル bitbucketにプッシュできない


bitbucketにプッシュする方法。
軽くハマったので備忘録。


```
git push -u origin --all
```
だと失敗するので、

```
git push --mirror git@bitbucket.org:[ユーザー名]/sample_app
```
こっちを使いましょう。
[Ruby on Rails]画像投稿ボタンをFont Awesomeのアイコンにする方法

##概要
表題の通りですが、調べるとHaml記法で書かれた投稿しか見つけられず、今のところHaml記法を使っていない私にはわかりづらかったので、メモがてら共有させていただきます。

##環境
Ruby:2.6.3
Rails:5.1.6
bootstrap:4.4.1
FontAwesome 

##方法
1.file_fieldで画像投稿ボタンを表示。
2.file_fieldボタンによって出力されるinputタグを見えなくする(dislay:none)。
3.file_fieldの上にFont Awesomeのアイコンをiタグで表示。
4.iタグをlabelタグで囲って、アイコンをボタンとして有効にする。

```erb:home.html.erb
<%= form_for(@dreampost) do |f| %>
  <div class="field">
    <%= f.text_area :content, placeholder: "投稿できます" %>
  </div>
  <div class="space-between">
    <span class="picture">
　    <label for="dreampost_picture">
  　    <i class="far fa-image"></i>
      </label>    
      <%= f.file_field :picture, placeholder: '&#xf0a8',accept: 'image/jpeg,image/gif,image/png' %>
      <div class="clear"></div> 
    </span>
  <%= f.submit "送信", class: "btn btn-primary" %>
<% end %>
```
```scss:custom.scss
.space-between { display: flex; justify-content: space-between; }

.picture>input { display: none; }

.picture>label { margin-bottom: 0; float: left; }

.fa-image { color: #fff; float: left; }

.fa-image::before { font-size: 2rem; }

.clear { clear: both; }
```

![スクリーンショット 2020-02-22 10.08.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555201/66a5d41e-cfea-16eb-46fc-f4e20a75bea4.png)

#補足
div.space-betweenに{ display: flex; justify-content: space-between;}と、
labelタグとiタグにfloat:leftで、
アイコンを左寄せ、送信ボタンを右寄せにしています。

ご指摘などございましたら、ぜひよろしくお願いいたします。
URLでBase64を扱うお話。

# 結論
* URLでBase64を扱う場合はBase64urlを使用する。


# 背景
とあるデータに紐づいて発行したQRを読み込み、ユーザがどのQRを読み込んだかを一意に特定するためURLにクエリストリングとしてパラメータを埋め込む必要があった。

→ そこまで重要な情報ではないものの、平文で埋め込むのはあまりよろしくないと考えBase64でエンコードして埋め込むことにした。


# 試行内容

#### 1. Base64
クエリストリングの値をBase64でエンコードして埋め込む。

```text:example1
https://<domain>/<function>?param=QmFzZTY044Ko44Oz44Kz44O844OJ44GZ44KL44Go6KiY5Y+344KS5ZCr44KA44OG44K544OI44OR44Op44Oh44O844K/44CC
```

これはBase64で使用される記号、`"/" , "+" , "="`[^1] の3つがURI予約文字のため正しくURLが解釈されずNGです。
[^1]: 参考文献 RFC 3986 2.2.Reserved Characters より。


#### 2. Base64 + パーセントエンコーディング(URLエンコード)
クエリストリングの値をBase64でエンコードした後、さらにパーセントエンコーディングして埋め込む。

```text:example2
https://<domain>/<function>?param=QmFzZTY044Ko44Oz44Kz44O844OJ44GZ44KL44Go6KiY5Y%2B344KS5ZCr44KA44OG44K544OI44OR44Op44Oh44O844K%2F44CC
```

一見これで問題なさそうに見えたが、パーセントエンコーディングをデコードしてからURLを叩くアプリが存在[^2]するため、上記のBase64でエンコードしたのみの場合と同様の現象が起きるためこの方法もNG[^3]だった。

[^2]: Motorola社 moto g7 の標準カメラアプリのQR読み込み機能にて当該事象に遭遇。
[^3]: エンコード内容によっては記号が出てこないため、原因がすぐにわからずここで引っ掛かりました…。

#### 3. Base64url
クエリストリングの値をBase64urlでエンコードして埋め込む。

```text:example3
https://<domain>/<function>?param=QmFzZTY044Ko44Oz44Kz44O844OJ44GZ44KL44Go6KiY5Y-344KS5ZCr44KA44OG44K544OI44OR44Op44Oh44O844K_44CC
```

Base64urlとは、URLとファイル名で不都合が生じないよう記号を予約文字以外の記号に置き換え、(暗黙的にデータ長が判明している場合のみ)パディングの`"="`を取り除いた**変形Base64**[^4]です。
[^4]: 参考文献 RFC 3986 5.Base 64 Encoding with URL and Filename Safe Alphabet より。
具体的な対応を表.1に示す。
<br>
表.1 Base64 と Base64url の記号対応表

|変換対象2進数(10進数)	|Base64		|Base64url	|
|:--:			|:----:		|:---:		|
|111110(62)		|+		|-		|
|111111(63)		|/		|_		|
<br>
example1とexample3を比較すると、表.1の通り記号が置き換わっていることが確認できます。

なお、Base64urlへの変換関数があるかどうかは言語による様子。


# まとめ
* パーセントエンコーディングをデコードしてからURLを叩くアプリが存在するため、Base64をURL上で使用する場合にはBase64urlを使用すると安全。
* Base64urlへの変換関数が実装されていないことがあるため、必要に応じて変換関数を作成する必要がある。


# 参考文献
*  [RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax](https://tools.ietf.org/html/rfc3986)
* [RFC 4648 - The Base16, Base32, and Base64 Data Encodings](https://tools.ietf.org/html/rfc4648)
Selenium + VB.NET で RPA　2:準備

自身が「Selenium + VB.NET」による自動化で学んだことをまとめた第二回目。（前回は[こちら] (https://qiita.com/k_airyuu/items/150168d9594b23546b6b)）

今回は準備編です。
まずはベースとなるVB.NETのプロジェクトを、Visual Studio で作成します。
※自分は「Visual Studio Express 2015 for Windows Desktop」を利用しています。
##１）Visual Studio で新規プロジェクトを作成する
スタートページから　ファイル ＞ 新しいプロジェクト　を選択します。
<img width="500" alt="001.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/4d4a60f7-c1e1-b1bf-b3a3-f0339e96b1c9.png">

「新しいプロジェクト」ウィンドウが開いたら、左カラムから Visual Basic を選択後、中央の Windowsフォームアプリケーション を選択し、下部で適当な名前と保存場所を入力したらOKボタンを押します。
<img width="500" alt="002.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/bcc27135-6eef-0215-0830-7f66dc6d45a2.png">

新しいプロジェクトが作成されました。
<img width="500" alt="003.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/775ae1be-2e26-16ad-a5bb-6752e78e6602.png">

##２）Selenium Web Driver をインストールする
続いてこの２と次の３は「VB.NETからブラウザを操作するために必要な準備」となります。
Visual Studio のメニューから　表示＞その他のウィンドウ＞パッケージ マネージャー コンソール　を選択します。
<img width="500" alt="004.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/1c0b4b23-39cb-881b-8f61-8a5d151c864d.png">

開いた パッケージ マネージャー コンソール ウィンドウ 内に下記をコピペしてEnterキーを押します。

```
Install-Package Selenium.WebDriver
```
<img width="500" alt="005.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/38f88620-9fb0-22e3-37f0-b82eafdcf382.png">

「正常にインストールされました」と表示されればOKです。
<img width="500" alt="006.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/dc613f94-0588-7ae8-0287-cea5a27c478c.png">


---
__Selenium Web Driver と同じ手順でインストールできるライブラリ__
この後使うので、こちらも併せてインストールしておきます。

```
●zipを扱う（展開・圧縮）ためのライブラリ
Install-Package DotNetZip
```


```
●ブラウザのセレクトボックス内を選択するために必要なライブラリ
Install-Package Selenium.Support
```

---

##３）ブラウザ用ドライバを追加する
続いてブラウザ用のドライバを用意します。（ブラウザの種類ごとに用意されています）
自分はChromeを使うので、Chrome用のドライバを用意しました。

下記よりダウンロードできます。（ブラウザと同じバージョンのドライバを選びます）
https://sites.google.com/a/chromium.org/chromedriver/downloads

ダウンロードしたZIPファイルを展開し、任意の場所に置きます。（chromedriver.exe）

次に Visual Studio のソリューションエクスプローラーでプロジェクトを右クリックし　追加＞既存の項目 を選択します。
<img width="500" alt="007.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/2c868f5c-cf09-088d-8153-a401a0327701.png">

「既存項目の追加」ウィンドウが開くので、先に用意しておいたドライバ（chromedriver.exe）を選択して追加ボタンを押します。（選択できない場合はファイルの種類を「すべてのファイル」に変更すると選べるようになります）
<img width="500" alt="008.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/e155c8ce-1e32-3de0-3185-3c9a8e4bc56e.png">

ソリューションエクスプローラーにchromedriver.exeが追加されました。
<img width="300" alt="009.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/cfac196e-fe35-70a5-fa59-54c7545f3842.png">

##４）追加したドライバのプロパティを変更する
ソリューションエクスプローラーにあるchromedriver.exeを選択した後、プロパティウィンドウの「出力ディレクトリにコピー」のドロップダウンリストから「常にコピーする」を選択します。
<img width="300" alt="010.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575853/e9291225-77cc-ec95-827f-bd1d1a96fd6a.png">

次回は自動化したい処理を Visual Studio でコーディングしたいと思います。

[Selenium + VB.NET で RPA　3:ブラウザ操作](https://qiita.com/k_airyuu/items/b193da739e3bc043124a)　へ続く
非同期通信 Ajax　基礎文法 3

#はじめに
非同期通信を学んでいく上で、用語等を中心に整理していきます。
[非同期通信 2 はこちらをクリック願います。](https://qiita.com/raigakun/items/9f3f84014f4857dcba28)
フレームワークはRailsを前提として進めております。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。

#jbuilder:array!メソッド
- jbuilderという拡張子を持つテンプレートは、JSONという名前のjbuilderオブジェクトが自動的に利用できるようになる。
- jbuilderオブジェクトは、JSON形式に返すための便利なメソッドがたくさんある。
- 配列で返したい場合、array!を使用する。
  - JavaScript側に配列で値を送ることができる。

#keyupメソッド
- 文字の打ち込みが終わる。＝　キーを離したら処理させたい。

#val()
- フォームの値を取得する時
  
#emptyメソッド
- 指定したDOMの子要素のみ削除するメソッド。
- 指定したDOM要素全体を削除するれもremoveメソッドとは異なる。

例）$(".contents.row").empty();

#forEachメソッド
- 与えられた関数を配列に含まれる各要素に対して一度ずつ呼び出す。



#さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
自己紹介

#プロフィール
　愛知県内の大学でいろいろな勉強をしている学生です。
　ふらっといろんな勉強会に顔を出して楽しんでいます。
　ゲーム開発メインでほかにWEBアプリやHPデザインなど
　幅広くたしなんでおります。
　言語は現在、C、Java、C#、HTML、CSSを使った経験あり。

#趣味
　読書（実用書からラノベまで幅広く）
　音楽鑑賞（ボカロ、EDM、ゲーム音楽など）
　一人旅

#今年の抱負

ゲームを作ります!!!!頑張ります!!!!
Selenium + VB.NET で RPA　1:はじめに

自分はここ5年ほど、社内業務プロセスの自動化に取り組んでいます。（Windows環境）
始めは自身が担当する業務の「繰り返しの手作業」がどうしても面倒くさく、これをなんとかしたかった一心で、気づけば「RPA」のようなことをしています。

>RPA (Robotic Process Automation)は、コンピューター上で行われる業務プロセスを人に代わり自動化する技術です。人間が繰り返し行うクリックやキーボード入力など定常的な業務が自動化できることから、仮想知的労働者(デジタルレイバー)とも呼ばれています。
https://www.uipath.com/ja/rpa/robotic-process-automation

##主な自動化ツール（いままで）

__デスクトップの処理__
VB.NET

__Excelの処理__
ExcelVBA

__ブラウザの処理__
iMacros
　

これらを使うことで（人の手作業に比べ）、大幅な処理の効率化・精度向上を達成できたものの、課題はそれぞれの処理が「別」な点、でした。

>例
複数のExcelファイルをダウンロードする（iMacros）
　↓
ダウンロードしたファイルをリネームする（VB.NET）
　↓
リネームしたファイルを提出用のデザインに整形する（ExcelVBA）
　↓
完了

処理がバラバラだと作業の手数が増えてしまうので、一括処理する仕組みを「Selenium + VB.NET」で構築しました。
これにより、VB.NETのフォームで「処理開始ボタン」を１回押すだけで、あとはVB.NETのコードに沿って、「ダウンロード」「リネーム」「Excel整形」の処理を一括でできるようになりました。

実は同じ処理を某RPAの開発ツールでも構築してみたのですが、うまく動いたり動かなかったりがあった一方、「Selenium + VB.NET」では動作の確実性が高いことも確認できたので、こっちのほうがもしかしたら良い筋なのかも（無料ですし）、と思ったりしています。（もちろんRPAツールへの習熟度が低かった、というのはあると思いますが…）

どこの職場にも日々繰り返すPC作業はあるかと思いますので、それを自動化するためのヒントになればと思い、自身が「Selenium + VB.NET」による自動化で学んだことを、ここに書きまとめていきたいと思います。

[Selenium + VB.NET で RPA　2:準備](https://qiita.com/k_airyuu/items/959d9819fb77ec6ac0d6)　へ続く
LINEボットを作って、webhookの受信をするいい方法の調査


# 理想やイメージ、アイディア

* cliでストリーミング
* 小規模
* 作業したくない
* セキュリティ
* コスト削減
* ランチャーなどで簡単立ち上げ

# ソリューション

## オンプレのチャット

今回はそこまで頑張りたくない

MattermostでSlackのメール連携みたいなことがしたい - Qiita
https://qiita.com/cocoon/items/16699f2aa4b319c6f0b0

Slackと違ってオンプレミス環境で作れるOSSチャット基盤4選＆RocketChatの基礎知識 (2/2)：OSSチャット基盤RocketChat入門（1） - ＠IT
https://www.atmarkit.co.jp/ait/articles/1608/18/news014_2.html


## webhook転送サービス

お金を払えば十分いけそう
もしくは、全部じゃなくてたまに確認したいレベルなら

Relay and proxy all your webhooks to public and internal destinations - Web Relay
https://webhookrelay.com/


## ログサービスに連携

フォーマットが違うので、直では接続できないかなあ

Plans - paid and free log management - Papertrail
https://www.papertrail.com/plans/

## ほか

* 直接macに転送（ローカルサーバーに開通）
* slack
* lambda
* vps

Forward の代替および類似のソフトウェア - ProgSoft.net
https://progsoft.net/ja/software/showoff-io

# 結果

独自ドメイン使えるプランのngrokが手頃で従量課金だったらいいのになあ
あ、DNSレコードを気軽に切り替えられるといいのかなあ

Ngrokを用いた簡単Botテスト作成 - Qiita
https://qiita.com/poccariswet/items/24fac246f8760abfb51e

これでいくかな
fillnull

日本語版[SPL Example](https://splunkbase.splunk.com/app/3456/)用
cf. [fillnull](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/fillnull)
#説明
```
null値を指定された値に置き換えます。
null値は、特定の結果では欠落しているが別の結果では存在するフィールド値です。 
fillnullを使用して、nullフィールド値を文字列で置き換えます。 
フィールドリストを指定しない場合、fillnullはすべてのnull値を0（デフォルト）またはユーザー指定の文字列に置き換えます。
```

##特定の結果では欠落しているが別の結果では存在するフィールド値
`| eval baz=coalesce(foo,bar)` を使う時ですね。

```java:fillnull.spl
index=_internal 
| fillnull component value="NA"
```
`component`のフィールドを確認すると`component`フィールドがなかったイベントにもフィールドが作成されて、この場合_NA_が入力される。

#記述
```
fillnull [value=string] [<field-list>]
```
#オプション引数

|value|field-list|
|:-:|:-:|
|文字列<br>デフォルトは0|値を入れるフィールド|

#例１
```java:fillnull1.spl
| makeresults 
| eval a="" 
| table a,b,c,d 
| fillnull a b c d
```
##結果
| a | b | c | d |
|--:|--:|--:|--:|
| | 0 | 0 | 0 |
`null`と`値がない`を表してみた。

#例２
```java:fillnull2.spl
| makeresults 
| eval a="" 
| eval b=null(), c=""
| fillnull a b c d
```
##結果
| a | b | c | d |
|--:|--:|--:|--:|
| | 0 |  | 0 |
明示的に`null`にしてあげなきゃいけないと言う例

```java:null除外.spl
| makeresults 
| eval a="" 
| eval b=null(), c=""
| fillnull a b c d
| foreach * [ eval <<FIELD>> = nullif(<<FIELD>>,"")]
| fillnull
```
全部nullにしてしまえばこの通りしっかり動きます。
#例３
```fillnull3.spl
| makeresults
| fillnull a b c d
```
##結果
| a | b | c | d |
|--:|--:|--:|--:|
| 0 | 0 | 0 | 0 |
何はともあれフィールドを作りたい時は`fillnull`が一番早い
#まとめ
nullはSplunkにおいて非常にわかりづらい。
`where isnull()`が期待通りの動きをしなかったりする場合`| fillnull`で確認してみるとただの`値がない`だけかもしれません。
:sweat:`fillnull`の話で終わっていない。
方眼エクセルをぎりぎりなんとか妥協レベルできるにするお手軽な方法

0. 「挿入」＞「テーブル」
0. 「データ」＞「テーブルから」
0. PowerQueryが開くので、
「ホーム」＞「行の削除」＞「空白行の削除」
0. 「変換」＞「入れ替え」
0. 「ホーム」＞「行の削除」＞「空白行の削除」
0. 「変換」＞「入れ替え」
0. 「ファイル」＞「閉じて読み込む」

とすると、結合が解除されてデータのない行と列が削除されたテーブルができる。
あとはがんばろう。
Gitコマンドでxcrun: errorが出た時の対処

# はじめに
久々に自分のMacでGit使おうとしたら以下のエラーで動かなかったので、対処方法をメモしておきます。

```
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
```

# 環境
- macOS Catalina10.15.3
- git version 2.21.1 (Apple Git-122.3)

# 対処方法
Xcodeの開発者ツールが見当たらなくなってしまっていることが原因らしいので、ターミナルで以下を実行すると直りました。

```
xcode-select --install
xcode-select --reset
```

# おわりに
MacOSをアップデートするとあるあるネタらしいので、またあったときに慌てないようにしたいです。

# 参考ページ
https://apple.stackexchange.com/questions/254380/why-am-i-getting-an-invalid-active-developer-path-when-attempting-to-use-git-a
正規表現validation＿定められた文字が投稿された文字列に含まれる

【問題】
2行目のvalidationを完成させてください。ただし条件は、「YOUTUBE」という文字が投稿された文字列に含まれていることを確かめること。

class Impression < ActiveRecord::Base
  VALID_YOUTUBE_URL_REGEX = ???
  validates :url, presence: true, format: { with: VALID_YOUTUBE_URL_REGEX }
end

【解答】
class Impression < ActiveRecord::Base
  VALID_YOUTUBE_URL_REGEX = /\A.* YOUTUBE. *\z/
  validates :text, presence: true, format: { with: VALID_YOUTUBE_URL_REGEX }
end

【解説】
1)class Impression < ActiveRecord::Base

RailsでActive Recordのバリデーション (検証: validation) 機能を使って、オブジェクトがデータベースに保存される前にオブジェクトの状態を検証。バリデーションは、正しいデータだけをデータベースに保存するために行われます。正しいデータだけをデータベースに保存するのであれば、model.rbモデルレベルでバリデーションを実行するのが最適です。モデルレベルでのバリデーションは、データベースに依存せず、エンドユーザーがバイパスすることもできず、テストもメンテナンスもやりやすいためです。Railsではバリデーションを簡単に利用できるよう、一般に利用可能なビルトインヘルパーが用意されており、独自のバリデーションメソッドも作成できるようになっています。

2)VALID_YOUTUBE_URL_REGEX = /\A.* YOUTUBE .*\z/

Regexは、「Regular Expression、正規表現」の略。

「/」正規表現オブジェクトを作成する時に「/パターン/」の形式で作成が可能となるため操作したい文字列をスラッシュで挟む
「\A」文字列の先頭
「\z」文字列の末尾
「.」は改行を除く任意の1文字にマッチ。ただし、複数行モードでは改行にもマッチする(例は後述の参考URLの３番目ご参照)
「*」は直前の正規表現の0回以上の反復(例は後述の参考URL、最後のURLご参照)

3)validates :text, presence: true, format: { with: VALID_YOUTUBE_URL_REGEX }

validates: 検証対象のフィールド名を指定します。, presence: true presenceヘルバーは、指定された属性が「空でない」ことを確認します。trueで常に検証することを指定する、つまり入力済みかを常に検証, format: with:属性の値}
formatヘルパーは、withオプションで与えられた正規表現と属性の値がマッチするかどうかのテストによる検証を行います。デフォルトのエラーメッセージは「is invalid」です。

【参考】
https://railsguides.jp/active_record_validations.html
https://docs.ruby-lang.org/ja/latest/doc/spec=2fregexp.html
https://www.javadrive.jp/ruby/regex/repeat/index1.html
https://www.javadrive.jp/ruby/regex/repeat/index2.html