OmniAICreator/Qiita-1.07M huggingface dataset:
CLS対策が必要な要素の調べ方

## そもそもCLSとは
CLS(Cumulative Layout Shift)とは、Googleが掲げるUXを良くするのに必要な３つの指標の中の一つで、Webページ内でレイアウトが動く度合いを表しています。

レイアウトが動くとはどういうことかは、このページ内の動画がわかりやすいです。
https://web.dev/cls/

ECサイトの注文内容確認画面において、キャンセルボタンを押す瞬間にレイアウトが動いてしまい誤って購入してしまうという内容です。このようにレイアウトが動いてしまうサイトは、CLSスコアが低く評価されてしまいます。


CLSスコアの定義は、公式のウェブに関する主な指標レポートに記載があります。
https://support.google.com/webmasters/answer/9205520?ref_topic=7440006#about_data

CLSであれば、スコアが高いほど悪く、0.25以上の場合は[改善が必要]と定義されます。
![スクリーンショット 2020-10-20 10.27.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738154/3e565884-2351-93d8-0fe7-f9a7de680f92.png)

2021年にGoogleのランキング要因として、CLSスコアが組み込まれる事が決定しておりますので、
今は検索結果の順位が良くても、来年までに対策を済ませておかないと順位低下を招く恐れがあります。


## CLS対策が必要なページを調べる
Search Consoleにアクセスし[ウェブに関する主な指標]の[モバイル]及び[PC]の分類で、対策が必要な全体数を確認します。
![スクリーンショット 2020-10-20 10.38.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738154/8c8c7823-dc13-2218-b642-161cc8141f70.png)


これは、とあるECサイトにおける参考データですが、良好ステータスを示す緑線が地を這っている場合、CLS対策を早急に進めないと痛い目に遭うことが予想できます。

詳細なURLは、[レポートを開く]から詳細タブで表示されている[CLSに関する問題:0.25超え]をクリックすると確認することが出来ます。
![スクリーンショット 2020-10-28 13.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738154/91fb6db8-0c3c-da8c-7f07-c3f6a571669b.png)


## CLS対策が必要な要素を調べる
ChromeのLightHouseを使って調査していきます。
修正が必要がURLにページにアクセスし、開発者ツールを開いて[LightHouse]タブを表示します。

Categoriesの項目は、[Performance]のみにチェックを付けるとレポート結果が早く出力されるので、それ以外のチェックを外します。
Deviceは、SearchConsoleの[ウェブに関する主な指標]で確認した分類([モバイル]及び[PC])に応じて設定します。
![スクリーンショット 2020-10-28 13.21.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738154/92979235-be6b-00d1-2cf3-1b252f36e92c.png)

設定が完了したら、[Generate report]をクリックし計測が完了するまで待機します。
計測が完了したら、レポートの下にスクロールすると[Avoid large layout shifts]という項目を確認します。
レイアウトが動いている要素が表示されるので、この要素が動かないように対策すれば良いことがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738154/7c62f271-3ca9-4dbf-6aa9-b961a10d74f4.png)

しかし、あくまでレイアウトが動いている部分がわかるだけなので、検知された要素を固定化しただけでは対策として不十分な場合があります。

CLS対策の具体的な方法については、後日投稿予定です。
Gitの基本

<font color="Red">gitとは</font>
  ソースコードを始めとするファイルの変更履歴を管理するためのシステムです。
  変更履歴を記録するシステムののことをバージョン管理システムと言います。

<font color="Red">gitをなぜ使う必要があるのか</font>
ファイルの変更履歴を管理するため

<font color="Red">gitを使う上での利点</font>
何か問題があった時に過去のファイルに戻れるようにしておくため

<font color="Red">githubとは</font>
gitの仕組みを利用したwebサービスのこと。gitの機能に対してチーム開発の便利な機能と付け加え、
gitにおけるリモートリポジトリの役割もになっている。
github上にチームで共有のプロダクト(ソースコード)を配置し、開発者はgithub上からソースコードをコピーしたり、ソースコードをgithub上のリポジトリに反映させることができる
【AtCoder】出力方法

出力方法を工夫してコードを短くできる問題をまとめました。
この方法を知らなかった時は、全てリストにして、"".join(リスト）にして～とめんどくさいことをしていました。

##ABC148-B

問題自体は簡単ですが、出力方法を工夫すればコードが短くなります。
print()の引数に、end=""と付ければ改行されません。

```
n=int(input())
s,t=input().split()

for i in range(n):
    print(s[i]+t[i],end="")
```


##ABC137-B
if文で最後の文字の後には改行を入れています（入れなくても通るのですが、コードの正しさ的に入れましょう）。

```
k,x=map(int, input().split())

for i in range(x-k+1,x+k):
    if i<x+k-1:
        print(i,end=" ")
    else:
        print(i)
```
【Swift】Documentディレクトリのフルパスはビルドやアップデートの度に変更される罠


　Documentディレクトリのフルパスはビルドやアップデートの度に変更される事を知らずにハマってしまったので誰かの助けになればと思います。

##Documentディレクトリのフルパスを取得

```swift:
let documentPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].absoluteString
```

##printしてみる
```swift:
print(documentPath)
```
<code>出力結果<br>file:///var/mobile/Containers/Data/Application/<font color="red">914B4E18-01A6-4538-9AD7-3B9887FE4B13</font>/Documents</code>

##次にビルドを再度行い、Documentディレクトリのフルパスをprintした結果

<code>出力結果<br>file:///var/mobile/Containers/Data/Application/<font color="blue">A5A17321-C158-4A5B-B8C7-5CF53F0C78EF</font>/Documents</code>

##パスのApplication下の数列を比べてみる
◆Application/<font color="red">914B4E18-01A6-4538-9AD7-3B9887FE4B13</font>/Documents
◆Application/<font color="blue">A5A17321-C158-4A5B-B8C7-5CF53F0C78EF</font>/Documents

|Application下の数列|
|:---|
|914B4E18-01A6-4538-9AD7-3B9887FE4B13|
|A5A17321-C158-4A5B-B8C7-5CF53F0C78EF|

<b>ビルド（アップデート後）にこの数列が変更されているのがわかります。</b>

##まとめ
Documentディレクトリのフルパスをそのまま保存してデータの呼び出しに使うと、ビルドする度にURL先が見つからないという問題が発生してしまいます。
なので、ファイル名だけ保存して、その都度Documentディレクトリのフルパスを取得して繋げるというやり方で対応しました。

もし、他に何かいい対策があれば教えてください🙇‍♂️
<br>
PostgreSQLで全てのテーブル、カラムを検索対象として任意の値を検索する

## 概要
Constraintsが貼られていない、ER図などもないといったプロジェクトで、あるテーブルのカラム値が、他のテーブルのどのカラムの値と関連付けられているのかを調査する場合の最終手段。
表題の通り、全テーブル、カラムを検索対象として任意の値を検索する。

## 注意
結構時間がかかるし、テーブルが大きければ負荷がかかるかもしれないので、当然本番環境ではやらないほうがよい。

## 環境
- PostgreSQL 9.6

## 手順
Editorモードにする

```sql
postgres> \e
```

Editorが開いたら以下を入力し、`:wq`で保存して閉じる。

```sql
CREATE OR REPLACE FUNCTION search_columns(
       needle text,
       haystack_tables name[] default '{}',
       haystack_schema name[] default '{}'
)
RETURNS table(schemaname text, tablename text, columnname text, rowctid text)
AS $$
begin
     FOR schemaname,tablename,columnname IN
         SELECT c.table_schema,c.table_name,c.column_name
         FROM information_schema.columns c
         JOIN information_schema.tables t ON
           (t.table_name=c.table_name AND t.table_schema=c.table_schema)
         WHERE (c.table_name=ANY(haystack_tables) OR haystack_tables='{}')
           AND (c.table_schema=ANY(haystack_schema) OR haystack_schema='{}')
           AND t.table_type='BASE TABLE'
     LOOP
       EXECUTE format('SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L',
          schemaname,
          tablename,
          columnname,
          needle
       ) INTO rowctid;
       IF rowctid is not null THEN
         RETURN NEXT;
       END IF;
    END LOOP;
END;
$$ language plpgsql;
```

以下を実行して検索。

```sql
postgres> select * from search_columns('検索したい文字列');

-- 検索結果が以下のように表示される
 schemaname |      tablename      |  columnname   | rowctid
------------+---------------------+---------------+---------
 public     | sample_table_001 | sample_column_001 | (0,1)
 public     | sample_table_002 | sample_column_002 | (0,2)
```
Railsの勉強で学んだこと

##GETとPOSTのざっくりな違い
GET: リンクをクリックして見たいページに飛ぶときに使われる
POST: 基本的ににサーバーのDBにデータを保存したいときになどに使われる

##ストロングパラメーター
WEB上から入力されてきた値を制限することで不正なパラメータを防ぐ仕組み、
Mass Asignmentというセキュリティー問題を回避するために必要。

##シンボル
シンボルとは文字列を通し番号で管理しているもの
:name や　:userなど

##ハッシュ化

ある特定の文字列や数字の羅列を一定のルール（ハッシュ関数)に基づいた計算手順によって
別の値(ハッシュ値)に置き換えること

暗号化との違いは元に戻せるか否か
暗号化は戻せるが、ハッシュ値はハッシュ化作業を行った人も含めて誰も元に戻せない。

##メソッド

メソッドとは関数のことメソッドの定義は def と end の間に実行したい処理を挟む

```
def メソッド名
   やりたい処理
end
```
Ruby設定1

# 初めに



## 確認
```bash
(m・_・bp) mbp-2 17:04 ~ % ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19]
```
## 色々インストール
```bash
$ brew install openssl
$ brew install readline
$ brew install libyaml
$ brew install autoconf
```

## ruby-build
ruby-buildはrbenvのプラグインで、自動でrubyをビルドする。

```console
$ brew update
$ brew upgrade ruby-build

$ ruby-build --version
```
# 現在のバージョン確認

```
## .rbenvのinstall
```bash
(m・_・bp) mbp-2 17:10 ~ % brew install rbenv ruby-build
```

/etc/zprofileへの追記するために移動

```bash
(m・_・bp) mbp-2 17:12 ~ % cd /etc
(m・_・bp) mbp-2 17:16 /etc % sudo cp zprofile zprofile.org #念のため予備を作っておく
(m・_・bp) mbp-2 17:16 /etc % sudo vi zprofile

```

##rbenv PATH  zprofileに下記の事を追記
```
if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

(m・_・bp) mbp-2 18:06 ~ % source /etc/zprofile
```

## rbenvのinstall確認
```bash
(m・_・bp) mbp-2 17:22 ~ % rbenv -v
rbenv 1.1.2
```

## ruby-buildインストール,,,既にインストールしてた
```bash
(m・_・bp) mbp-2 17:35 ~ % brew install ruby-build
Warning: ruby-build 20200401 is already installed and up-to-date
To reinstall 20200401, run `brew reinstall ruby-build`
```
## rbenvで最新versionをinstall
```
(m・_・bp) mbp-2 17:22 ~ % rbenv versions
* system (set by /Users/uekiyoshihiro/.rbenv/version)
```

## rbenvでインストール
[Rubyの公式サイト](https://www.ruby-lang.org/ja/downloads/)
こちらのサイトをみて安定版の最新バージョンをインストール

```bash
 ~ % rbenv install -l

 ~ % rbenv install 2.7.1

 ~ % ruby -v

 ~ % rbenv install 2.6.5
```



## rubyのバージョンを切り替える
バージョン切り替えには、ディレクトリのみの設定orデフォ設定の2種類がある。

```bash
$ rbenv local <バージョン>
# 実行したディレクトリ配下で使うrubyのバージョンを変更
# 指定バージョンの .ruby-version が作成される

$ rbenv global <バージョン>
# デフォルトで使うrubyのバージョンを変更

$ rbenv local --unset
# ローカルバージョン指定の取消し
```
上記の通り、アプリごとに異なるバージョンのrubyを利用したい場合は、各ディレクトリで`rbenv local`を実行して、rubyのバージョンを指定。


ちなみにこれらのコマンドを実行すると、現在のディレクトリに 「.ruby-version」 というファイルが作成される。これは自動で使用するrubyのバージョンを変えるもの。


## その他：openssl
opensslはhttpsを使用するためのパッケージ。

```bash
$ which openssl
$ brew list openssl
$ openssl version
```

参考：[Mountain Lion に rbenv を導入](http://hrysd.hatenablog.com/entry/2012/11/13/012153)

```console
(m・_・bp) mbp-2 19:48 ~ % rbenv versions
  system
  2.6.5
  2.6.6
* 2.7.1 (set by /Users/uekiyoshihiro/.ruby-version)



```

![](2020-05-14-20-00-49.png)


```console
(m・_・bp) 14:57 ~/Desktop/vsnote2.0/ruby/lib/rubybook_2 % gem install minitest -v 5.10.1
Fetching minitest-5.10.1.gem
Successfully installed minitest-5.10.1
Parsing documentation for minitest-5.10.1
Installing ri documentation for minitest-5.10.1
Done installing documentation for minitest after 0 seconds
1 gem installed

```
アプデでzshが初期化したらコマンドプロンプトの設定やり直し

## terminal
1.  zshrc
2.  ls /etc/zshrc
3.  PS1='%F{2}(m・_・bp)%f %T %F{4}%~%f %# '
4.  [とりあえずZshを使えば良いんだろう？](https://qiita.com/ktr_type23/items/3eb782f98c7a5f4c60b0)
3つのFORMをJS→VUE.JSに書き換え

#更新内容

##10/31
　回答が得られず苦労している。JSの不満の要点を書いておく。

・AJAXポスト送信をあくまでバックエンドで処理させたい。
→　このままJSエンジニアにサーバー領域にまで踏み込んでほしくないから。

せめてやるなら、モデルまでNODE.JSで受け取ってからにしろと言いたい。
最近、ＳＰＡじゃなくてユニバーサルとか言い出したのは、
フロントエンジニアが弱気になって来たか、もしくはバックエンドが暇になって来たかの
どちらかだろう・・・

・FLASK側の処理は、あくまでフレームワークでやりたい。
→　せっかく用意されたフレームワークなので、後発のＪＳのためにまで仕様変更したくない

後輩は、先輩に対して、配慮しろと言いたい
最近のＪＳ見てて思うのだが、熟年エンジニアの流儀作法をしらないやつが
参入してきている感がある。結局は先人の教訓に従い、いまさらＴＳなどど言い始めている。
俺は、その流暢は好きではない。

動的型付け言語のプライドを捨ててはいけない


##10/28
　自分で解決できず、サイトに丸投げ質問中

https://stackoverflow.com/questions/64583679/i-want-to-rewrite-3-input-form-form-from-js-to-vue-js
https://teratail.com/questions/300488



#内容
　既にできているノーマルのJSをどうにかして、Vue.Jsに置き換えてみる練習
　単純に同じフォームが３つあるので、Vue.Jsでコンポーネントできるのではと思った
　簡略化のために、フォームのバリデーションは無し

#ポイント
　FLASK側は、FLASK-FORMを使いフォームを名前で分岐している。
　Jinjaには、form1,form2,form3を渡している。

#元のコード
```javascript

{% extends "layout.html" %}
{% block body %}

<div id="content">
    <div class="container-fluid">
        <h1>データ1の読込</h1>
        <p>
            <form class="form form-horizontal" method="POST" action="{{url_for('data_import')}}"  enctype="multipart/form-data">
                {{ form1.hidden_tag() }}
                {{ form1.file }}
                <input type="submit" >
            </form>
        </p>
        <hr>
        <h1>データ2の読込</h1>
        <p>
            <form class="form form-horizontal" method="POST" action="{{url_for('data_import')}}"  enctype="multipart/form-data">
                {{ form2.hidden_tag() }}
                {{ form2.file }}
                <input type="submit" >
            </form>
        </p>
        <hr>

        <h1>データ3の読込</h1>
        <p>
            <form class="form form-horizontal" method="POST" action="{{url_for('data_import')}}"  enctype="multipart/form-data">
                {{ form3.hidden_tag() }}
                {{ form3.file }}
                <input type="submit" >
            </form>
        </p>
        <hr>
</div>
</div>

{% endblock %}

```

```python
#データインポート処理
@app.route('/import',methods=["GET", "POST"])
def data_import():
    number_form = UploadForm()
    label_form = UploadForm()
    xxx_form = UploadForm()

    if request.method == "POST":
        if number_form.validate_on_submit():
            filename = secure_filename(number_form.file.data.filename)
            number_form.file.data.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        elif label_form.validate_on_submit():
            filename = secure_filename(label_form.file.data.filename)
            label_form.file.data.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        elif xxx_form.validate_on_submit():
            filename = secure_filename(label_form.file.data.filename)
            xxx_form.file.data.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

        return redirect(url_for('data_import'))

    return render_template( 
        'import.html',form1=number_form,form2=label_form,form3=xxx_form)
```
Rで無限混合ガウスモデルへの道.2

# 記事の目的
平均も分散も確率変数の場合の混合ガウスモデルのギブスサンプリングをRで実装することです。
参考書籍: [佐藤一誠. ノンパラメトリックベイズ. 講談社. 2016](https://www.amazon.co.jp/%E3%83%8E%E3%83%B3%E3%83%91%E3%83%A9%E3%83%A1%E3%83%88%E3%83%AA%E3%83%83%E3%82%AF%E3%83%99%E3%82%A4%E3%82%BA-%E7%82%B9%E9%81%8E%E7%A8%8B%E3%81%A8%E7%B5%B1%E8%A8%88%E7%9A%84%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%81%AE%E6%95%B0%E7%90%86-%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%BD%90%E8%97%A4-%E4%B8%80%E8%AA%A0/dp/4061529153/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=&sr=)
この書籍のアルゴリズム4.3に対応します
※目次2, 4のコードは[前回](https://qiita.com/Tatsuki-Oike/items/07c8bc0530173f50ed85)と同様です。


# 目次

[1. モデルの説明](#1-モデルの説明)
[2. 使用データ](#2-使用データ)
[3. 分散固定の混合ガウスモデルのギブスサンプリング](#3-分散固定の混合ガウスモデルのギブスサンプリング)
[4. クラスタリング確認](#4-クラスタリング確認)

#1. モデルの説明
![IMG_0165.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/775500/a9e06607-1827-df49-4452-f7ac2d6734f9.jpeg)

#2. 使用データ
```R:
> X <- iris[,1:4]
> D <- ncol(X)
> N <- nrow(X)
> head(X)
  Sepal.Length Sepal.Width Petal.Length Petal.Width
1          5.1         3.5          1.4         0.2
2          4.9         3.0          1.4         0.2
3          4.7         3.2          1.3         0.2
4          4.6         3.1          1.5         0.2
5          5.0         3.6          1.4         0.2
6          5.4         3.9          1.7         0.4
> 
```

#3. 分散固定の混合ガウスモデルのギブスサンプリング
```R:
library(dplyr)
library(mvtnorm)
library(MCMCpack)
# (1)
K <- 3
# (2)
u <- matrix(rep(apply(X, 2, mean),each=K), nrow=K, ncol=D)
# (3)
r <- 1
a0 <- 1
b0 <- 1
# (4)
pi <- rep(1/K, K)
t <- 1

# (5)
alpha <- 1/K
max.iter <- 30
Norm <- {}
z <- {}
n <- {}
x.k <- matrix(NA, nrow=K, ncol=D)
tmp.sum2 <- {}
a <- a0+N*D/2

set.seed(100)
for(s in 1:max.iter){
  tmp.sum1 <- 0
  # (ⅰ)
  for(i in 1:N){
    for(k in 1:K){
      Norm[k] <- dmvnorm(X[i,], u[k,], diag(D)/sqrt(t))*pi[k]
    }
    z_prob <- Norm/sum(Norm)
    z[i] <- rmultinom(1, 3, z_prob) %>% which.max()
  }
  # (ⅱ)
  for(k in 1:K){
    n[k] <- z[z==k] %>% length()
    x.k[k,] <- X[z==k,] %>%  apply(2, mean)
    u[k,] <- rmvnorm(1, n[k]*x.k[k,]/(n[k]+r), diag(D)/sqrt(t*(n[k]+r)))
  }
  # (ⅲ)
  for(k in 1:K){
    for(i in 1:N){
      if(z[i]==k){
        tmp.sum1 <- tmp.sum1 + unlist(X[i,]-x.k[k,]) %*% unlist(X[i,]-x.k[k,])
      }
    }
    tmp.sum2[k] <- tmp.sum1/2+n[k]*r/(2*(r+n[k]))*(t(x.k[k,]) %*% (x.k[k,]))
  }
  b <- b0 + sum(tmp.sum2)
  t <- rgamma(1,a,b)
  # (ⅳ)
  alpha <- alpha + n
  pi <- rdirichlet(1, alpha)
}

```

#4. クラスタリング確認
```R:
library(cluster)
par(mfrow=c(1,2))
clusplot(X, iris[,5], color=TRUE, shade=FALSE, labels=4, lines=0)
clusplot(X, z, color=TRUE, shade=FALSE, labels=4, lines=0)
```

>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/775500/e54fd03b-c966-32e4-8e57-47cb8522d773.png)
Rで無限混合ガウスモデルへの道.1

# 記事の目的
分散固定の場合の混合ガウスモデルのギブスサンプリングをRで実装することです。
参考書籍: [佐藤一誠. ノンパラメトリックベイズ. 講談社. 2016](https://www.amazon.co.jp/%E3%83%8E%E3%83%B3%E3%83%91%E3%83%A9%E3%83%A1%E3%83%88%E3%83%AA%E3%83%83%E3%82%AF%E3%83%99%E3%82%A4%E3%82%BA-%E7%82%B9%E9%81%8E%E7%A8%8B%E3%81%A8%E7%B5%B1%E8%A8%88%E7%9A%84%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%81%AE%E6%95%B0%E7%90%86-%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%BD%90%E8%97%A4-%E4%B8%80%E8%AA%A0/dp/4061529153/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=&sr=)
この書籍のアルゴリズム4.2に対応します

# 目次

[1. モデルの説明](#1-モデルの説明)
[2. 使用データ](#2-使用データ)
[3. 分散固定の混合ガウスモデルのギブスサンプリング](#3-分散固定の混合ガウスモデルのギブスサンプリング)
[4. クラスタリング確認](#4-クラスタリング確認)

#1. モデルの説明

![IMG_0159.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/775500/49df6fa8-7aff-2aa1-d1bf-fec04d1f7cbd.jpeg)

#2. 使用データ
```R:
> X <- iris[,1:4]
> D <- ncol(X)
> N <- nrow(X)
> head(X)
  Sepal.Length Sepal.Width Petal.Length Petal.Width
1          5.1         3.5          1.4         0.2
2          4.9         3.0          1.4         0.2
3          4.7         3.2          1.3         0.2
4          4.6         3.1          1.5         0.2
5          5.0         3.6          1.4         0.2
6          5.4         3.9          1.7         0.4
> 
```

#3. 分散固定の混合ガウスモデルのギブスサンプリング
```R:
library(dplyr)
library(mvtnorm)
# (1)
K <- 3
# (2)
u <- matrix(rep(apply(X, 2, mean),each=K), nrow=K, ncol=D)
# (3)
var <- 1
pi <- rep(1/K, K)

# (4)
max.iter <- 30
Norm <- {}
z <- {}
n <- {}
set.seed(1)
for(s in 1:max.iter){
  # (ⅰ)
  for(i in 1:N){
    for(k in 1:K){
      Norm[k] <- dmvnorm(X[i,], u[k,], diag(D))
    }
    z_prob <- Norm/sum(Norm)
    z[i] <- rmultinom(1, 3, z_prob) %>% which.max()
  }
  # (ⅱ)
  for(k in 1:K){
    n[k] <- z[z==k] %>% length()
    x.k <- X[z==k,] %>% apply(2, mean)
    u[k,] <- rmvnorm(1, n[k]*x.k/(n[k]+var), diag(D)/(n[k]+var))
  }
  s <- s+1
}

```

#4. クラスタリング確認
```R:
library(cluster)
par(mfrow=c(1,2))
clusplot(X, iris[,5], color=TRUE, shade=FALSE, labels=4, lines=0)
clusplot(X, z, color=TRUE, shade=FALSE, labels=4, lines=0)
```

>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/775500/d330e90a-155f-6c11-a705-346b87a93653.png)
【備忘録】Fizz_Buzz問題について(RubyonRailsの動き方)

#本稿について
PFを作成後、改めてFizz_Buzz問題をRubyで入力していたところ、
少し理解が深まったので、備忘録として残します。

#Fizz_Buzz問題とは
プレイヤーは円状に座る。最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの次の数字を発言していく。ただし、3で割り切れる場合は「Fizz」（Bizz Buzzの場合は「Bizz」）、5で割り切れる場合は「Buzz」、両者で割り切れる場合（すなわち15で割り切れる場合）は「Fizz Buzz」（Bizz Buzzの場合は「Bizz Buzz」）を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。
Wikiより転記：https://ja.wikipedia.org/wiki/Fizz_Buzz

これをプログラムで書くと、条件分岐（if文等）と繰り返し（for文等）が必要になるため、初学者の練習問題となることが多い。

```ruby:fizz_buzz.rb
def fizz_buzz(number)
	if number % 15 == 0
		puts "fuzz_buzz"
	elsif number % 5 == 0
		puts "buzz"
	elsif number % 3 == 0
		puts "fuzz"
	else
		puts number.to_s
	end
end

puts "1以上の数値を入力してください"
for i in 1..5 do
  print fizz_buzz(gets.to_i)
end
```

##RubyonRailsで言うと
controllerで下記のような、プログラムをよくみる

```ruby:users_controller.rb
def show
	@user = User.find(params[:id])
end
```

###fizz_buzz.rbで言うところのgets.to_iがviewファイルで行われ、controllerの処理が実行されている。

####わかっている人にとっては、当たり前だろうが府に落ちたので

以上です
【Ruby on Rails】サクッとブラウザでページタイトルを表示

# 目標
![スクリーンショット 2020-10-26 13.32.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/3fc9d30b-b095-b2e7-fbba-4e082cfec9a1.png)



# 開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

# ベースとなるタイトルの編集

```rb:application_helper.rb
module ApplicationHelper
  def full_title(page_title = '')
    base_title = "アプリ名"
    if page_title.empty?
      base_title
    else
      "#{ page_title } | #{ base_title }"
    end
  end
end
```

# head内のタイトルを編集
```erb:application.html.erb
<head>
  <title><%= full_title(yield(:title)) %></title>
</head>
```
# 各ページのタイトルを追加
今回はaboutページがあると想定します。
追加場所は一番上でOKです。

```erb:app/views/homes/about.html.erb
<%= provide(:title, 'サイトについて')%>
```

Qiita記事のようにカラムを使用してタイトルを表示する場合は
下記のように記述すればOKです。

```erb:app/views/homes/about.html.erb
<%= provide(:title, @genre.name)%>
```

# まとめ
これらを実施する事により、ユーザーが現在どの位置にいるかを把握することができ、
ユーザーの離脱率改善に繋がりますので、必須の搭載機能だと言えます。

またtwitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら　https://twitter.com/japwork
Qiita Markdown 書き方

# はじめに
これから記事を投稿していくために,
Qiitaの書き方を自分なりにまとめてみることにしました。

# 目次
1.枠を作る
2.引用
3.Markdownのエスケープ
4.水平線
5.リンク




### １．枠を作る
***
>```
テスト
```

<b>背景色を黒で囲む・コードの挿入</b>
<b>記述方法: </b>

　◾上下に空行をいれて、バッククオート3つで文字を囲む。
上のバッククオートの横に(例)ruby:hoge.rbと記述すると、コードブロックの左上にファイル名が入る。


>(空行)
 \```
>       テスト

>\```
>(空行)

***



>`テスト`

<b>背景色をグレーで囲む枠</b>
<b>記述方法:</b>

　◾ バッククオート１つで文字を囲む
>　\`テスト\`


### ２．引用
***

>引用
>>引用

<b>記述方法:</b>
　◾文章の最初に  > をつけ、下は空行にする


>\>テスト

### ３．Markdownのエスケープ
***
>\>テスト

<b>記述方法:</b>
　◾文章の最初に  \ をつけ、下は空行にする

>\\>テスト

### 4．水平線
***

>***
* * *
---

<b>記述方法:</b>
　◾ * か - を3つ以上を書く。

>\***
\* * *
\---

### 5．リンク
***

> [Qiita](http://qiita.com "Qiita")

<b>記述方法:</b>
　◾ [リンクテキスト]（リンク先）と書きます。

>\[リンクテキスト](URL "タイトル")　タイトル付き
\[リンクテキスト](URL)　タイトルなし

## 参考


[Markdown記法チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
Railsで簡単な通知機能（フォローされた時のみ）

Railsでの簡単な通知機能です。（とりあえずフォローされた時のみ）

##ルーティングの設定

```config/routes.rb
  resources :notifications, only: [:index]
```

##コントローラの作成

```
$ rails g controller notifications
```

##モデルの作成

```
$ rails g model Notification visitor_id:integer visited_id:integer
```

```
$ rails db:migrate
```

##モデルとアソシエーションの設定

```app/models/user.rb
  has_many :active_notifications, class_name: "Notification", foreign_key: "visitor_id", dependent: :destroy
  has_many :passive_notifications, class_name: "Notification", foreign_key: "visited_id", dependent: :destroy

  def create_notification_follow!(current_user)
    temp = Notification.where(["visitor_id = ? and visited_id = ? ",current_user.id, id])
    if temp.blank?
      notification = current_user.active_notifications.new(visited_id: id)
      notification.save if notification.valid?
    end
  end
```

```app/models/notification.rb
  belongs_to :visitor, class_name: 'User', foreign_key: 'visitor_id'
  belongs_to :visited, class_name: 'User', foreign_key: 'visited_id'
```

##コントローラの設定

```app/controllers/relationships_controller.rb
  def create
    @user = User.find(params[:user_id])
    current_user.follow(params[:user_id])
    @user.create_notification_follow!(current_user) #追記部分
    redirect_to request.referer
  end
```

```app/controllers/notifications_controller.rb
  def index
    @notifications = current_user.passive_notifications.order(created_at: :DESC)
  end
```

##ビュー（通知一覧）の設定

```app/views/notifications/index.html
<h1>おしらせ</h1>
<% if @notifications.exists? %>
  <% @notifications.each do |notification| %>
    <table>
      <tr>
        <td>
          <%= attachment_image_tag notification.visitor, :image, size: "50x50" %>
        </td>
        <td>
          <%= link_to user_path(notification.visitor) do %>
            <%= notification.visitor.name %>
          <% end %>
        </td>
        <td>
          からフォローされました。
        </td>
        <td>
          <%= " (#{time_ago_in_words(notification.created_at)}まえ)" %>
        </td>
      </tr>
    </table>
  <% end %>
<% else %>
  <p>おしらせはありません</p>
<% end %>
```
カラムのBoolean型とは

<h3>Booleanとは、一般的に真と偽のような２つの状態を表すデータ型のこと</h3>
____

Railsではbooleanにデフォルト値を渡してあげることによって、
true,false,nilという３つの情報を必ず2つに収束するようにできる
nilというものが存在しないようにチェックすることができる。

なので必ずデフォルト値を入れてあげるとよい。
音ゲーを作って思ったこと

#改善点
- コライダーで取得判定するな
  - 連打がきつい
  - やるならタップした軸のノーツをリスト化して現在時間から一番近いノーツを取得してくるとかがいいと思う
- アプリを触ってるというより画像をタップしてる感が無くならない(個人的な感想)

#良い点
- 時間でスコア判定をしている
- タップのSEが気持ちいい
- スピードを変えてもノーツの配置がちゃんと出来てる


#感想
- やっぱり一度作ってみないと何が[楽しくないか/違和感があるか]わからないから好きなものほど作っておいたほうがいいなと思った
- ゲームをしていて自分がオモシロイと思ったところをメモしておくと将来の自分が楽できる
  - ただし、新しいものには常に触れ続けないといけない
phoenixでWebアプリを作る　準備編


## Gigalixrの登録
頑張って登録する。

## GithubActionの準備

Githubのmasterリポジトリに登録したら、自動的にGigalixrにデプロイするよう設定する。

専用のプラグイン？が開発されているので、ありがたく使わせてもらう。
https://github.com/mhanberg/gigalixir-action

```
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the action will run. Triggers the workflow on push or pull request events but only for the master branch
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  deploy:
    if: github.ref == 'refs/heads/master' # Only run this job if it is on the master branch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          ref: master # Checkout out master instead of the latest commit
          fetch-depth: 0 # Checkout the whole branch
      - uses: mhanberg/gigalixir-action@v0.3.0
        with:
          GIGALIXIR_USERNAME: ${{ secrets.GIGALIXIR_USERNAME }}
          GIGALIXIR_PASSWORD: ${{ secrets.GIGALIXIR_PASSWORD }}
          GIGALIXIR_APP: my-gigalixir-app # Feel free to also put this in your secrets
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          MIGRATIONS: false # defaults to true
```

環境変数の登録は、リポジトリのSettings->Secretsから行う。

## go-transproxyの準備
（プロキシ環境下での作業を強いられている場合）
頑張って準備する。

## サンプルの実行

ElixirとPhoenixとPostgresSQL入りのコンテナを作ったので、プルして、

```
docker pull bleach31/phoenix:1.5.5
```

~~docker run -p 4000:4000 -it bleach31/phoenix:1.5.5~~
PostgresSQLのサービス起動が必要なので、いろいろとオプションをつけて起動する。

```
docker run -p 4000:4000 --privileged -d bleach31/phoenix:1.5.5 /sbin/init
docker exec -it {コンテナ名} /bin/bash
```
```
systemctl start postgresql

cd /home/
```

新しくプロジェクトを作る場合。

```
mix phx.new hello
```
続きの場合はGit cloneなりをして、

```
cd hello/

mix deps.get
mix ecto.create
cd assets/
npm install

mix phx.server
```
localhost:4000でアクセス！
さらに、githubのmatsterブランチにpushすれば自動的にgigalixirにデプロイされて、外部公開されます。
pandocでmarkdown→LaTeX変換するとき、hyperlinkを出力しない

pandocを使えば、いちいち`\subsubsection{小見出し}`とか明らかに日本語向けでないtexの悪しき記法を使うことなくmarkdownで色んなものが書けてチョー快適であるが、pandocくんは結構余計なおせっかいをしてくる。

# 問題

```kinotake.md 

# 背景

## きのたけ戦争

日本人は元来きのこ軍とたけのこ軍に分かれ、現在もなおどちらが優れているなどと血で血を洗う争いが続けられている。これがきのこたけのこ戦争である。なおこの戦争の黒幕が明治であることは言うまでもない。

```

こんな文書を`pandoc kinotake.md -o kinotake.tex`すると、

```Tex
\hypertarget{ux80ccux666f}{%
\section{背景}\label{ux80ccux666f}}

\hypertarget{ux304dux306eux305fux3051ux6226ux4e89}{%
\subsection{きのたけ戦争}\label{ux304dux306eux305fux3051ux6226ux4e89}}

日本人は元来きのこ軍とたけのこ軍に分かれ、現在もなおどちらが優れているなどと血で血を洗う争いが続けられている。これがきのこたけのこ戦争である。なおこの戦争の黒幕が明治であることは言うまでもない。

```
こんなふうに変換してくる。なんかゴテゴテしてない？

# \hypertarget ってなんだ？

[こちら](https://www.isc.meiji.ac.jp/~mizutani/tex/link_slide/hyperlink.html)を参照。生成されるpdfファイルにページ内リンクやら何やらをつけてくれるプラグインらしい。
便利だが、いらんこともある。何より日本語をunicodeに変換してつけてるせいで汚い。

# 解決法
[StackOverflow](https://stackoverflow.com/questions/52341046/remove-hypertarget-from-pandoc-latex-output)に解決策が載っていた。
`pandoc -r markdown-auto_identifiers`すればいいらしい。実際にやってみた。

```TeX
\section{背景}

\subsection{きのたけ戦争}

日本人は元来きのこ軍とたけのこ軍に分かれ、現在もなおどちらが優れているなどと血で血を洗う争いが続けられている。これがきのこたけのこ戦争である。なおこの戦争の黒幕が明治であることは言うまでもない。
```

すっきりした。解決。
長いのでaliasとかに登録しておくと便利かもしれない。
Head First  Machine Learning

機械学習(ML)を利用する機会が増えてきました。しかし、機械学習(ML)未経験者や初学者の人にとって、いきなりコードを書いて、機械学習(ML)のモデルを構築するのは非常に難易度が高いです。そこで、今回は、機械学習(ML)未経験者や初学者の人がノーコードで機械学習(ML)のモデルを構築し、実行できる方法についてご紹介します。

## 大まかな流れ

大まかな流れは以下の通りです。

1. 環境構築
    1. Azure の無料アカウントを作成する
    2. Azure Machine Learning を作成する
    3. Azure Machine Learning Studio を作成し、起動する
2. 機械学習(ML)
    1. 自動 ML(Auto ML)を行う

## 環境構築
### Azure の無料アカウントを作成する

以下にアクセスして、Azure の無料アカウントを作成してください。

[Azure portal](https://azure.microsoft.com/ja-jp/?WT.mc_id=AZ-MVP-5001601)

### Azure Machine Learning を作成する

1. 以下の順にメニューを押下します<br/>[Machine Learning] -> [Azure Machine Learning の作成]<br/>
![2020-10-28-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/ff7fd0d2-f048-048f-b600-e5e8d4bf78e9.png)
![2020-10-28-2.1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/91ecd039-22b9-23f7-d55c-2beff8f11e50.png)
2. 以下の項目を適宜入力します<br/>
サブスクリプション： 任意<br/>
リソース グループ： 任意<br/>
場所： 東日本
![2020-10-28-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/90766a6a-85d7-003d-41d5-32c8e93f4045.png)
3. 上記入力後、[確認および作成]ボタンを押下すると検証が行われ、検証に成功すれば[作成]を押下します。すると、デプロイが開始します
4. デプロイ完了後、[リソースに移動]を押下します

### Machine Learning Studio を作成し、起動する

1. [今すぐ起動する]を押下します
![2020-10-28-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/1aebb25f-6360-42fe-fbf1-d3bde51e6634.png)
2. [新しいワークスペースの作成]を押下します
![2020-10-28-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/4d49f20f-2c5f-715e-b5f7-40b0d4f062a4.png)
3. 以下の項目を適宜入力します<br/>
サブスクリプション： 任意<br/>
リソース グループ： 任意<br/>
ワークスペース名： 任意<br/>
リージョン： 東日本
![2020-10-28-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/fb613d5e-bb82-1a5d-7a2e-aca607426050.png)
4. 上記入力後、[確認および作成]ボタンを押下すると検証が行われ、検証に成功すれば[作成]を押下します。すると、デプロイが開始します
5. デプロイ完了後、1. の[今すぐ起動する]を再度押下します

## 機械学習(ML)
### 自動 ML(Auto ML)を行う

1. 自動 MLの下の[今すぐ開始]を押下します
![2020-10-28-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/3b03bc91-2528-b671-a23d-3169a5ed6933.png)
2. [新しい自動 ML の実行]を押下します
![2020-10-28-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/a1a09619-f043-16bb-86a4-6adafc705bbd.png)
3. データセットの選択で、[データセットの作成]すると選択肢が出てきます。機械学習(ML)に使いたいローカルファイルをアップロードします。
![2020-10-28-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104744/fd6ac4a6-e011-726c-89a6-d072495bd676.png)
4. データセットが作成できたら、実行の構成をしていきます。実験名、ターゲット列、コンピューティングクラスターの選択をします。
5. 最後にタスクを「分類」を選択します。<br/>
分類： りんごかアップル、赤か青か黄のようにカテゴライズ(分類)する際に選択します<br/>
回帰： 値段のような連続する数値を予測する際に選択します<br/>
時系列の予測： 気温のような時系列に基づいて予測する際に選択します
6. 上記選択後、[終了]を押下すると、自動 ML(Auto ML)が実行され、しばらく待っていると結果が表示されます
【CEDEC 2020 フォローアップ】監修を素早く正確に ~複雑なIPプロジェクトの効率化事例~

![eyecatch_2010CEDECvol1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/bf974d94-f3dc-f3b3-1837-b3b592e0c300.png)

※ 本稿は <a href="https://tech.drecom.co.jp/?_src=qiita">Tech Inside Drecom</a> に掲載された記事、「<a href="https://tech.drecom.co.jp/cedec-2020-ip-project/?_src=qiita">【CEDEC 2020 フォローアップ】監修を素早く正確に ~複雑なIPプロジェクトの効率化事例~</a>」の Qiita 出張版です。

---

第２プロダクション 技術グループ 所属の二宮です。

本稿では、CEDEC2020で登壇させていただきました以下セッションの補足として、当日会場で頂いたご質問に関しましてお答えしていきます。

<b>監修を素早く正確に – 複雑なIPプロジェクトの効率化事例</b>
<a href="https://cedil.cesa.or.jp/cedil_sessions/view/2269" target="_blank">https://cedil.cesa.or.jp/cedil_sessions/view/2269</a>

# 質疑応答
## CSV のチケット制作は Unity のマスターデータから作成していますか？
今回の場合は、チケット自体はマスターデータからではなく、IPホルダー様から頂くリソース一覧表(Excel形式)を参照して作成していました。成果物として出てくる監修資料内の文字列(キャラ名等)が、マスターデータを参照し自動入力されています。

## Unity でのツール制作にかかった時間はどのくらいですか？
どのようなツールにするか仕様をIPホルダー様、社内と決定しつつ試行錯誤のα版ツール作成が２ヶ月ほど、ツールの実作成が２ヶ月ほど、バグ修正や実稼働後のFB対応で１ヶ月ほど、計５ヶ月ほどかかりました。 このツール制作はスクラム開発で、ゲーム機能開発と並行して行なっておりました。

## 自動トリミングは座標固定ですか？キャラ画像部分の範囲検出ツールなど使用されていますか？
シーンに配置された監修対象Prefabのbottom-left座標を検出、この座標からwidth * height を画像全体から切り取る機能を実装しております。
![ef51443e290f71d005bcbfc3f75c43bd-1024x573.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/b688cc74-0bc9-6cdc-9d2e-40e57d21cb69.png)


## Ruby の選定理由はなんですか？
当初、NPOI（C#）を扱っていたのですが、ツール作成者である自分が、Rubyのaxlsxの方が実装しやすいと感じたのが１つ理由です。もう１つとして、C#でのエクセル作成は２分ほどかかっていましたが、Rubyではそこを３０秒で完結することができたため、動作的にもRubyを選定しました。

## 自動化ツールにテキスト間違いなどのエラーチェック機能は付いていますか？
そのような機能はございませんが、マスターデータ自体をテキスト監修に出しているため、文言間違いなど予め防ぐことが可能となっております。

## 一度 Redmine を経由して Ruby にデータを流していますが、Redmine に送る同様の情報を元に Ruby に送ることは出来なかったのでしょうか？
そちらも可能ではありましたが、今回は状態把握を関係各所で行うためRedmineを使っての管理を行うことが先行していたため、Redmineと各ツールを連携させるという想定でツールを作成し始めたため、RubyもRedmineからデータ取得をする形となりました。

## ラフ段階やトリミング前など、制作途中段階での監修はおこなっていないのでしょうか？
イラストの段階で事前のチェックなどはある程度行われており、全部作ってから「違ったので描き直し」というのは発生しませんが、正式な最終チェックはゲーム画面の状態で行うという流れになっております。

---

Tech Inside Drecom の最新の情報は Facebook や Twitter からお届けしています、フォローよろしくおねがいします！

* Twitter: <a href="https://twitter.com/DRECOM_TECH" target="_blank">@DRECOM_TECH</a>
* Facebook: <a href="https://www.facebook.com/tech.inside.drecom" target="_blank">tech.inside.drecom</a>

※ その他の Tech Inside Drecom の記事は、<a href="https://tech.drecom.co.jp/?_src=qiita">コチラ</a>からお探しいただけます！

<a href="https://tech.drecom.co.jp/?_src=qiita">![picture_pc_842afe4c369ce3c3019e33e16729d2c6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/828e98dd-fd1a-89ac-73a5-366ba08062a5.png)</a>
Node.js + socket.io の簡易チャットアプリをコンテナ化したメモ

# 背景
Node.js + socket.io の簡易チャットアプリをコンテナ化した時のメモ

# リンク集
#### [Node.js Web アプリケーションを Docker 化する](https://nodejs.org/ja/docs/guides/nodejs-docker-webapp/)
Hello Worldを返す簡易Node.jsサーバーを作ってコンテナ化するドキュメント。ほぼ忘れかけているNode.jsの記憶を取り戻すことができた。

#### [Socket.io#Get Started](https://socket.io/get-started/chat/)
socket.ioを使って簡易的なアプリを作ることができる

# サンプルコード


```json:package.json
{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "shogo suzuki",
  "main": "socket_server.ts",
  "scripts": {
    "start": "node socket_server.js"
  },
  "dependencies": {
    "express": "*",
    "socket.io": "^2.3.0"
  }
}
```


```dockerfile:Dockerfile

FROM node:14.13
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "node", "socket_server.ts" ]
```

```html:index.html

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: 0.5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <script src="/socket.io/socket.io.js"></script>
  <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
  <script>
    $(function () {
      var socket = io();
      $('form').submit(function(e){
        e.preventDefault(); // prevents page reloading
        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
      });
      socket.on('chat message', function(msg){
        $('#messages').append($('<li>').text(msg));
      });
    });
  </script>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>
```

```ts:socket_server.ts

var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', (socket) => {
  console.log('a user connected');
  socket.on('chat message', (msg) => {
    io.emit('chat message', msg);
  });
});

http.listen(3000, () => {
  console.log('listening on *:3000');
});
```

# 実行

```
docker build -t socket-example:1.0 .
docker run -p 3000:3000 -d socket-example:1.0
```
Dockerfile の ベストプラスクティス を抽出しました！

# はじめに
今回は[前回](https://qiita.com/yassun-youtube/items/2ed29e97ec61582f7668)に引き続き、Dockerの基本的な書き方を紹介します。

本家の[**Best practices for writing Dockerfiles**](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)から抽出しました。


動画で確認したい方はこちらをどうぞ。
[【YouTube動画】 Dockerfileのベストプラクティスを紹介！ あなたはいくつできてますか？](https://youtu.be/Oeu1Ykg-eGs)
[![Collation](https://img.youtube.com/vi/Oeu1Ykg-eGs/0.jpg)](https://www.youtube.com/watch?v=Oeu1Ykg-eGs)

# .dockerignoreを使う
.gitignoreみたいなファイルで、コンテナに加えないファイルを設定できます。

```
# .dockerignore
*/tmp
```

# コンテナ1つに1プロセス
1つのコンテナ (Dockerfile) でRailsやMySQL, Nginxなどを起動するのは止めましょう。
バージョンアップが難しくなりますし、原因の切り分けも大変です。

# レイヤ数を最小にする
DockerはRUN, ADD, COPYを実行するたびに、一時的にイメージが作られます。
Dockerfileの読みやすさにも関わってくるので、なるべく分けないようにしましょう。

# マルチステージビルドを使う
以下のようにFROM内のAS句で名前付けします。
名前付けしたものを新しくレイヤーを作り直す時に宣言することで、中間のイメージを除くことができます。

例ではGoを使ってますが、Nodeでも役立ちそうです。

```dockerfile
FROM golang:1.11-alpine AS build

#### パッケージ導入 & ビルド ####
RUN apk add --no-cache git
RUN go get github.com/golang/dep/cmd/dep

COPY Gopkg.lock Gopkg.toml /go/src/project/
WORKDIR /go/src/project/
RUN dep ensure -vendor-only

COPY . /go/src/project/
RUN go build -o /bin/project
#### ビルド終了 ####

# 新しくレイヤーを作り直す
FROM scratch
COPY --from=build /bin/project /bin/project
ENTRYPOINT ["/bin/project"]
CMD ["--help"]
```

# 引数は適切に！
引数はアルファベット順に並べると、可読性が上がります。

```dockerfile
RUN apt-get update && apt-get install -y bzr cvs git
```

# alpineイメージで軽くする
alpineイメージを使うと、容量を小さくできます (5 M以下)。
ちなみに、alpineはBusyBoxにパッケージマネージャー apkを加えたイメージです。
ホストOSの負荷を小さくできるので、開発環境とかで良いかもしれません。


# upgradeはしない
upgradeするなら、ベースイメージのバージョンを上げましょう。

# ADDよりもCOPYを使う
ADDは多機能なコマンドで、予期しない動きをすることがあります。
ホストOSからゲストOSにファイルを移動させるなら、COPYを使いましょう。

# rootユーザーを使わない
セキュリティ上あまりよろしくないので、USERを追加する方が良いです。

# まとめ
今回はDockerfileの書き方を紹介しました。
具体的な書き方や使い方は、別記事で紹介します！

[twitter](https://twitter.com/yassun_youtuber)や[youtube](https://www.youtube.com/channel/UCajrdoGzHzDogrNrLYYmGsg/featured?view_as=public)でのコメントもお待ちしています！

## 追記
より詳しい話は@zembutsu さんによる訳を読んでみると良さそうです！
[Dockerfileを書くためのベストプラクティス【参考訳】](https://qiita.com/zembutsu/items/a96b68277d699f79418d)
Windows版VSCodeの絶対に覚えておきたいショートカットキー５選

# 初めに
普段Visual Studio Codeで最もよく利用する5つのショートカットキーをメモしておくことにした。

# 開発環境
Windows 10
Visual Studio Code 1.49.3

# ショートカットキー
## 1. ファイル検索
`Ctrl` + `P` + 検索文字入力
![スクリーンショット (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396527/c0e61a60-b721-fdf6-d336-459e2af18df5.png)

## 2. 指定した行にジャンプ
`Ctrl` + `G` + 行数入力
![cntrg.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396527/63d20825-bf64-cfc5-6a00-d3a82fffd97f.png)
## 3. 文字列置換
`Ctrl` + `H`
※ワークスペース内一括置換：`Ctrl` + `Shift` + `H`
![スクリーンショット (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396527/98359714-98f4-5a95-4d02-b4d21d67b2b9.png)
## 4. マルチカーソル
`Alt` + `Shift` + ドラッグ
![スクリーンショット (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396527/ae9ce6b1-f86b-a092-6357-f3d5e158c950.png)

## 5. コメントアウト
`Ctrl` + `/`

**ASP**
![スクリーンショット (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396527/23961a7b-8f22-3783-e5ed-00978685356e.png)
**JavaScript**
![スクリーンショット (16).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396527/4b6a8ee5-7332-aaac-ec78-ed5e96d15051.png)
**SQL**
![スクリーンショット (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396527/1e1fe752-5a51-91c1-ba7c-70120c244743.png)


# 最後に
今後は、他のショートカットキーも駆使して、より効率的な開発を行う。
VBScript「Filter関数」を使用時の注意点

#本記事の目的
VBSの中で「配列Aの中から、文字列Bに一致する配列の値を抜き出す」ための関数として**Filter関数**があります。こちらを業務で実装する時に気づいた仕様上の注意点について、ナリッジメモとして残したいと思います。初めて本関数を使用する方などの、実装時の補助線となれば幸いです。

#Filter関数について
基本形式は下記のようになります。
抽出モード（抽出結果をTrue or Falseで返す）と、文字列比較のモード（バイナリモード(0) or テキストモード(1)）については省略可能です。


```vb

Filter(配列A, 文字列B,(抽出モード),(文字列比較のモード))
```



#注意点
この関数で、文字列Bと一致するかの処理を行う際、値同士は**「完全一致」**ではなく**「部分一致」**で比較されます。例を挙げると、「9」に一致する値を抜き出す時、範囲が「1~10」の時と「1~20」の時では、下記のような違いがでます（「テストコード」→「実行結果」の順に記載します）。

####テストコード

```vb

dim moji
dim array
dim extraction
dim index
dim result

' 実際に処理する際は、どちらかのmojiをコメントアウト
' 1~10の時
moji = "1,2,3,4,5,6,7,8,9,10"

' 1~20の時
moji = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20"

array = Split(moji, ",")
extraction = Filter(array,9)

For index = 0 To UBound(extraction)
	result = extraction(index)
	response.write "抜き出し結果：" & result & "<br>"
Next

response.end
```


####実行結果


1~10の時

```
抜き出し結果：9
```



1~20の時

```
抜き出し結果：9
抜き出し結果：19
```


上記のような結果となるため、Filter関数の使用は**「指定する文字列が、部分的に一致すればOKな時に限られる／完全一致させたい時はNG」**という点に注意して頂ければと思います。

#補足
もし完全一致での比較を行いたい場合、**StrComp関数**で文字列同士の比較を行い、その戻り値を使用する等の方法があります。[こちらのサイト](https://www.kanaya440.com/contents/script/vbs/function/string/strcomp.html
 "こちらのサイト")に分かりやすい使用方法が記載されていますので、ご参照下さい。
【JS】Chromeでは動作OK。だが、iOS、safariでReferenceError!?!?

#エラー内容
```sample.js
let a = xxxxx.join('');
```

```
ReferenceError: Can't find variable: xxxxx
```

Chromeでは、出なかった参照エラー。
ブラウザ特有のエラーということで、```「safariのみ ReferenceError JS」```などのワードでググってみましたが、jQueryのクリックイベントのDOM参照方法であったり、cssの```cursor: pointer;```を足してみるであったり、自分のエラーと本質的に異なるものばかりで諦めていました。

また、clickイベントで出たーエラーでだったので、イベントが発生するところとしない箇所でconsoleで確認してみたりと時間をかなり掛けました。

しかし、原因はとても単純でした・・・

#解決策
**変数宣言を変えるだけ。**

```sample.js
var rivalNumText = xxxxx.join('');
```

まさかのvarに変えるだけでした。。。

#原因は結局？？
varよりも、letの方が比較的新しいということで使用していました。
~~しかし、**```let```はSafariやIE、iOS、またAndroidのブラウザではサポートされていないみたい**です。~~

~~動作スピード的にはletやconstを使用する方が早いみたいですが、ブラウザ対応の面で考えるとその点についても考慮する必要があるみたいです。~~

**●＜コメントより修正＞**
```let```が使用できないのは、自分自身の環境の問題の可能性もあります。
対応しているブラウザであれば、ブラウザの更新で```let```を使用できるよう解決できます。

今回で言えば、```let```がどのブラウザで使えるのか[こちらのサイト](https://caniuse.com/?search=let)から確認できるみたいです。

#参考
[JavaScriptのvarとletについて](https://teratail.com/questions/35670)
Dockerfile、docker-compose.ymlを作ってwindows10、Linux、ラズパイでnodejsを動かす

以前書いた下記、記事の続きでDockerfileとdocker-compose.ymlを作って、動かす手順まで今回記載します。
https://qiita.com/MCYamamoto/items/4d424af9573fa90edf61

## 最終的なフォルダ構成
まず、最終的なフォルダ構成です。
下記のようになります。

```
baseフォルダ
+docker-compose.yml
+cont
 +env
  +Dockerfile
   +deploy //デプロイ対象のソースコード(今回はnodejs)
    +package.json
    +package-lock.json
    +build
     +jsファイルたち
  +share //ホストとコンテナの共有フォルダ
```

## Dockerfileをつくる

[参考URL]
https://qiita.com/pottava/items/452bf80e334bc1fee69a

全体的な流れとしては、上記を参考にした。
インストール必要なものをインストールしながらコマンドをメモして、最終的なDockerfileを作るというもの。

### 1. Dockerイメージを決める。
   ラズパイはARMのため、ARMに対応したイメージとしてDebianにした。
   [参考URL]
   https://qiita.com/koduki/items/0ed303dac5d32646194f

### 2. bashのコンテナを起動する。
<pre>
$ sudo docker run -it -v $(pwd):/tmp/share debian:buster /bin/bash
-it:ターミナルで操作可能に
-v:コンテナとのフォルダ共有
</pre>

### 3. 必要なものをインストールする。
動かしたいプログラムによって必要なパッケージをインストールする。

```
apt-get install パッケージ名
```

といった感じです。

なお、注意点としては、Dockerfileに書く場合はインストールを止めないため"-y"オプションが必要です。

最終的にはnodeとsqliteしか必要なかったので、コンテナイメージをnodeにしてしまう方が良いのですが、
過程を残すということで、最終的にできたのは下記になります。

やっていることとしては、下記になります。
- deploy対象のコードをコピー
- 必要なものをOSにインストール
- deployフォルダ配下のnodeに必要なパッケージを「npm install」でインストール

```
#Dockerfile

FROM debian:buster

COPY deploy/ /home/deploy
WORKDIR /home/deploy

RUN apt-get update
RUN apt-get install -y cmake
RUN apt-get install -y libssl-dev
RUN apt install curl
RUN apt-get install -y sqlite3 libsqlite3-dev
RUN apt-get install -y nodejs npm && npm install n -g && n 12.18.4
RUN npm install
```

## docker-compose.ymlをつくる
先ほど作ったDockerfileをコンテナイメージとして、最終的にdeployフォルダ配下のnodeが自動起動するものにしました。
<補足>

```
version: "3.8"
services:
  cont:
    build:
      context: ./cont/env
      dockerfile: Dockerfile
    container_name: CONT-1
    tty: true
    volumes:
      - "./cont/env/share:/tmp/share"
      - ".:/workspace"
      - "./cont/env/deploy/build:/home/deploy/build"
    working_dir: /home/deploy/build
    command: npm run start
```

<補足>
package.jsonに下記記載して、buildフォルダ配下のプログラムが動くようにしています。

```
  "scripts": {
    "start": "node ./build/main.js",
  },
```


## docker-compose起動
作成したフォルダ環境一式を各OS(Windows10、Linux、Raspi)の任意のフォルダに配置して下記実行すると、すべて同じ動きします。


```
sudo docker-compose up --build
```

## (おまけ)Vscodeでのデバッグ環境作る

[参考URL]
https://tech-lab.sios.jp/archives/21675
https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0

Visual Studio Code 上でf1メニューまたは左下に現れる緑色のアイコンをクリックして「Remote-Containers: Open Folder in Container...」を選択し、docker-compose.ymlがあるフォルダを選択すると
しばらくするとコンテナが実行され、コンソールでデバッグ操作できます。

vscode、docker便利、、
param is missing or the value is empty が表示された時の対処法

##解決したいこと
フォームの入力欄を入力後、送信ボタンを押すと、
param is missing or the value is empty と表示されること。

##エラー解決方法の結論
ストロングパラメーターのrequireオプションを消し、permitメソッドだけにすることで解決しました。

##エラー解決までの過程
###1 paramsの中身を確認した。

```
def create
     binding.pry
     @item_request = ItemRequest.new(item_params)
     @item_request.save
     redirect_to root_path
  end
```

```
private

  def item_params
     params.require(:item_request).permit(:name, :number, :store, :month_id, :day_id, :hour_id, :minute_id, :prefecture_id, :city, :house_number)
  end
end
```
上記のように、コントローラーファイルに、binding.pryと記述し、その後、フォームを再度送信した後、ターミナルで動作が止まるので、paramsと入力した。
すると、

"name"=>"j", "number"=>"j", "store"=>"j", "month_id"=>"4", "day_id"=>"6", "hour_id"=>"4", "minute_id"=>"3", "prefecture_id"=>"3", "city"=>"横浜市緑区", "house_number"=>"567-3", "commit"=>"依頼する", "controller"=>"items", "action"=>"create"} permitted: false>
```
と表示され、パラメーターは正常に送れていることが分かった。



###2　privateメソッドでrequireを使う必要はないのでは？と思ったので、requireを消去した。
```private

  def item_params
     params.permit(:name, :number, :store, :month_id, :day_id, :hour_id, :minute_id, :prefecture_id, :city, :house_number)
  end

```
すると,param is missing or the value is empty のエラーは解決することができました。
原因は、おそらく、このフォームが複数テーブルへのデータの保存をするフォームだったので、requireでモデルを指定すると、指定されたモデルは一つだけになってしまい、permitの引数のキーはそのモデルには存在しなかったと考えられます。

以上になります。
*(注)　僕のエラー解決法は、一例にすぎません。
xml.etree.ElementTreeの使い方

Python 3.8.2

[xml.etree.ElementTree --- ElementTree XML API](https://docs.python.org/ja/3/library/xml.etree.elementtree.html#elementtree-xpath)
# パース
ファイルから

```Python
import xml.etree.ElementTree as ET
tree = ET.parse('country_data.xml')
root = tree.getroot()
```

文字列から


```Python
root = ET.fromstring(country_data_as_string)
```

# 検索
タグで現在の要素の *直接の子要素* のみ検索

```Python
# Listが返ってくる
list = root.findall('country'):
```

タグで最初に見つかった要素だけ検索

```Python
elem = root.find('country'):
```

XPath式で検索

* [サポートされている XPath 構文](https://docs.python.org/ja/3/library/xml.etree.elementtree.html#elementtree-xpath)

```Python
root.findall("./country/neighbor")
```
# コンテンツと属性へのアクセス

コンテンツにアクセス

```Python
rank = country.find('rank').text
```

属性にアクセス

```Python
 # どちらでも
 country.get('name')
 country.attrib['name']
```




# 子要素の生成

```Python
elem = ET.SubElement(root,'country')
elem = ET.SubElement(root,'country', attrib={'name':'Liechtenstein'})
```

# 子要素の削除

```Python
>>> for country in root.findall('country'):
...     # using root.findall() to avoid removal during traversal
...     rank = int(country.find('rank').text)
...     if rank > 50:
...         root.remove(country)
...
```

# 出力

sys.stdoutに出力

```Python
ET.dump(root)
```

ファイルに出力

* 改行されないので見にくい


```Python
tree = ET.ElementTree(root)
tree.write('filename', encoding="utf-8", xml_declaration=True)
```

改行付きでファイルに出力

```Python
import xml.dom.minidom as md
document = md.parseString(ET.tostring(root, 'utf-8'))
with open(fname,'w') as f:
    document.writexml(f, encoding='utf-8', newl='\n', indent='', addindent='  ')

```
InfluxDBでSQLライクにクエリを書く時のTips

InfluxDBは，SQLライクな記法で記述できるものの完全なサポートはされていないのでハマったポイントをメモしておく．

# like句は使えない

`LIKE %hoge%`みたいな構文は使えない．かわりに以下を使う．

```sql
select "name" from users where "name" =~ /hoge/
```

否定の場合は以下

```sql
select "name" from users where "name" !~ /hoge/
```

# group byとcount()で集計できない

SQLでは項目別の数を数えたい場合は，以下で行えます．

```sql
select name,count(*) from users group by name
```

InfluxDBでこれをやると以下のエラーが出力されます．

```
mixing aggregate and non-aggregate queries is not supported
```

これは，アグリゲートクエリと非アグリゲートクエリが混在していることによるエラーです．

参考: https://community.influxdata.com/t/err-mixing-aggregate-and-non-aggregate-queries-is-not-supported/10508

# inner joinやouter joinがない

以下に対処方法が書かれている．

https://community.influxdata.com/t/substitution-for-inner-join/489
Sentryの情報にアプリケーションのバージョン情報を追加する方法

# 前提
Sentryを使用してエラー情報を検知しているアプリケーションであること。

# 使用言語、フレームワーク
- Java 8
- Spring Boot(Maven)

# 概要
Sentryに送信されるエラー情報がいつのバージョンのアプリケーションで発生したエラーのものであるか確認できるようにしたい。

# メリット
- 発生したエラーのアプリケーションのバージョンの特定が一目でわかる。
- Sentryの画面で特定のバージョンで発生したエラーの一覧を以下のように検索することができるようになる。

|![スクリーンショット 2020-10-15 11.33.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171963/2ca08a7f-2337-93ba-cb18-b4ee4dcdd305.png)|
|:--|

# 前提条件
- アプリケーションのバージョンが定義されていること。
- リリースの度にバージョンが更新されていること。

以下の定義ファイルの `<version>` 内をSentryに送信します。
今回は、バージョン情報をSentryにタグとして送信します。

### 定義ファイル

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmls="~">
　　　　　：
	<groupId>com.example</groupId>
	<artifactId>myproject</artifactId>
	<version>100.0.100</version>
　　　　　：
</project>
```

# 修正手順
以下の順番で修正を行います。
1. 依存関係の追加
2. エンドポイントの追加
3. エンドポイントに表示する情報の追加
4. Sentryへの送信処理の追加

## 1. 依存関係の追加

```xml:pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
```

## 2. エンドポイントの追加

```yaml:application.yml
management:
  endpoints:
    web:
      exposure:
        include: "info"
      base-path: "/"
```
base-pathは環境に応じて変更してください。

## 3. エンドポイントに表示する情報の追加

```yaml:application.yml
info:
  application:
    version: @project.version@
```

ここまで設定すると `http://localhost:8080/info` にアクセスすることで以下のようにここまでの手順で設定したバージョン情報を確認することができます。

```
{"application":{"version":"100.0.100"}}
```

## 4. Sentryへの送信処理の追加

設定ファイル：@SpringBootApplicationアノテーションを設定しているクラスに以下の処理を追加します。
※ すでにSentryへの送信処理を実装している場合は、`version` 関連の処理を追加してください。
　（引数の追加とtagの送信部分です。）
※ 戻り値の型は

```java

  @Bean
  public HandlerExceptionResolver sentryExceptionResolver(
    @Value("${sentry.url:#{null}}") Optional<String> sentryUrl,
    @Value("${info.application.version:#{null}}") Optional<String> appVersion) {

    if (sentryUrl.isPresent()) {
      try {
        SentryClient sentryClient = Sentry.init(sentryUrl.get());
        // ここで、タグとしてバージョン情報を追加しています。
        appVersion.ifPresent(s -> sentryClient.addTag("version", s));
      } catch (InvalidDsnException e) {
        LOGGER.warn(e.getMessage(), e);
      }
    }
    return new SentryExceptionResolverImpl();
  }
```

※ `sentry.url` も `info.application.version` と同様に `application.yml` に定義しています。

# 設定後
上記設定を完了後、アプリケーション内でエラーが発生した場合、以下のような `version`のタグが表示されるようになります。
versionの数値部分をクリックすることで、冒頭でメリットとして挙げた検索結果を確認できます。

|![スクリーンショット 2020-10-15 11.27.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171963/bfa70909-b5ea-8390-9030-d4d6840d1e47.png)|
|:--|