OmniAICreator/Qiita-1.07M huggingface dataset:
Dockerのコンテナとホストとの関係の条件付け

# はじめに
Dockerは多くのIT開発企業で導入されている環境構築を楽にする技術です。
Dockerで作成したコンテナはホスト（自身のPCやAWSなどのクラウド）に対して、ファイルを読み込んだり、また、ホストのサーバーからコンテナへ接続したり、というような関係を持ちます。
それらの関係の条件を指定するために、docker runにオプションを付けて、実行します。
今回はコンテナとホストとの関係の条件付けのためのオプションを紹介します。


# 今回紹介する内容(docker runコマンドとオプション)
* コンテナからホストのファイルに接続できるようにする (docker run -v)
* ユーザーIDやグループIDの指定する (docker run -u)
* ホストのポートとコンテナのポートをつなげる (docker run -p)
* コンテナがアクセスできるCPUやメモリの上限を設定する(docker run --cpus)(docker run --memory)


### コンテナからホストのファイルに接続できるようにする (docker run -v)

ホストのファイルをコンテナの中にも存在するように振舞わせることをマウントと言います。
コンテナは誰かに使ってもらったり、手軽に実行させたりできるように、サイズが小さいことが望ましいので、可能な限りコンテナ自体にファイルを設置しないようにします。
例えば、コードのファイルはホストに置いておき、コンテナからホストのコードのファイルを読み込ませるという場合、コードのファイルをコンテナにマウントさせる、と言います。

```ターミナル
docker run -it -v (ホストのパス):(コンテナのパス) (DockerImageの名前 or ID) bash

例) docker run -it -v /Desktop/sample_dir:/new_dir (DockerImageのID) bash
=> コンテナのnew_dirというディレクトリにホストのDesktopに存在するsample_dirというディレクトリがマウントされます。
(コンテナにnew_dirというディレクトリが存在しない場合は、コンテナにnew_dirというディレクトリが自動で作成されます。)
```


### ユーザーIDやグループIDの指定する (docker run -u)

ホストのファイルをコンテナでマウントさせる場合、ユーザーIDやグループIDを指定しないと、コンテナがルート権限を持ってアクセスすることができてしまいます。
ルート権限がコンテナ側にあると、コンテナからホストのファイルを作成したり、編集したり、様々なことができてしまいます。
ルート権限を持たせたくない場合には、ユーザーIDやグループIDを指定して、マウントさせます。

```ターミナル
docker run -it -u (ユーザーID):(グループID)

例) docker run -it -u $(id -u):$(id -g) -v /Desktop/sample_dir:/new_dir (DockerImageのID) bash
=> ユーザーIDとグループIDが指定して、ホストのファイルをマウントしたコンテナが作成される。
```


### ホストのポートとコンテナのポートをつなげる (docker run -p)

ポートとはサーバーの中の特定の場所です。
例えば、サーバーに複数のサービスがあった場合、IPアドレスだけではどのサービスに接続するか分からないため、ポートを指定します。
作成したコンテナを一つのWebサービスとする場合、コンテナのポートとホストのポートをつなげる必要があります。

```ターミナル
docker run -it -p (ホストのポート):(コンテナのポート)

例) docker run -it -p ３０００:3000 rails bash
=> railsというDockerImageからコンテナが作成され、railsのデフォルトのポート3000に繋がるため、ホスト側でlocalhost:3000にアクセスするとrailsにアクセスすることができます。
```

### コンテナがアクセスできるCPUやメモリの上限を設定する(docker run --cpus)(docker run --memory)

コンテナが動く時、ホストのCPUやメモリを使います。
例えば、一つのコンテナが限界までCPUやメモリを使ってしまった場合、メモリが枯渇してシステム全体が落ちてしまう可能性があります。
そのようなリスクを避けるために、それぞれのコンテナに対して、CPUやメモリの上限設定をします。

```ターミナル
docker run -it --cpus (論理コア数) --memory (メモリ容量)

例) docker run -it --cpus 4 --memory 2g ubuntu bash
=> ubuntuというDockerImageからコンテナが作成され、このコンテナが使えるCPUの論理コアの上限は4つで、メモリの上限は2ギガとなります。
（コンテナのCPUやメモリを確認したい時は、"docker　inspect (コンテナID)"を入力します。）
```

※自身のPCのCPUやメモリが知りたい場合はターミナルに以下の入力をすると確認できます。

* sysctl -n hw.logicalcpu_max  => CPU（論理コア数）
* sysctl hw.memsize  => メモリ(byte)



# 参考
Udemy
>かめれおん講師　「米国AI開発者がゼロから教えるDocker講座」
>>https://www.udemy.com/share/103aTRAEAdd1pTTHoC/

有料ですが、初学者の私にも非常に理解しやすかったです。

# 最後に
本投稿が初学者の復習の一助となればと幸いです。
複数のCSVファイルをマージするコマンド

カレントディレクトリ内にあるCSVファイルをマージします。


## 各CSVにヘッダが無い場合

````bash
cat *.csv
```

ワイルドカード`*`でファイル名を展開し、`cat`で結合して出力します。たとえばディレクトリ内のCSVファイルが`1.csv`、`2.csv`、`3.csv`ならば、`cat 1.csv 2.csv 3.csv`と同じ結果になります。ファイルに出力する場合は、

````bash
cat *.csv > result
````

のようにリダイレクトすれば、`result`に出力されます。


## 各CSVにヘッダがある場合

各CSVにヘッダがある場合は、1行目を除いてマージします。

````bash
find -name "*.csv" -exec sed -e '1d' {} \;
````

`find -name [pattern]`は、カレントディレクトリ内のファイル名が`[pattern]`にマッチするファイルの一覧を取得します。`find`コマンドに`-exec`オプションをつけると、マッチした各々のファイルに対して、引数で与えたコマンドを実行します。引数内の`{}`はマッチしたファイル名に変換されて実行されます。たとえば、`1.csv`、`2.csv`、`3.csv`がマッチしたとすると、`sed -e '1d' 1.csv`、`sed -e '1d' 2.csv`、`sed -e '1d' 3.csv`が各々実行されます。最後の`;`は`-exec`オプションの引数の終わりを意味しますが、シェルの構文と解釈されないよう、`\;`とエスケープしています。

`sed`は文字列の抽出や置換をするコマンドです。`sed -d '[N]d' [file]`で、`[file]`のN行目を除いて出力します。

また、次のように書くこともできます。

````bash
find -name "*.csv" | xargs -n 1 sed -e '1d'
````

`xargs [command]`は、標準入力を`[command]`の引数に渡します。`-n`オプションは、一度にコマンドに渡す引数の数を指定します。上のコマンドでは、たとえば標準入力に`1.csv`、`2.csv`、`3.csv`が渡された場合、`sed -e '1d' 1.csv`、`sed -e '1d' 2.csv`、`sed -e '1d' 3.csv`が各々実行されます。このオプションを指定しないと、標準入力が`sed -e '1d' 1.csv 2.csv 3.csv`のようにまとめてコマンドに渡されます。後者は「`1.csv`、`2.csv`、`3.csv`をマージした結果」の1行目を取り除いて出力することになり、1つ目以外のヘッダは残ったままになります。また、`cat *.csv | sed -e '1d'`とした場合も同様に、結合後のファイルの1行目を取り除くことになり、期待する結果になりません。

`sed`の代わりに`tail`コマンドを使ってもできます。

```bash
find -name "*.csv" -exec tail -n +2 {} \;
```

または

```bash
find -name "*.csv" | xargs -n 1 tail -n +2
```

`tail -n [- or +N] [filename]`で、 `filename`の後ろを出力します。`-N`を指定した場合は後ろからN行を出力します。`+N`を指定した場合はN行目から末尾までを出力します。

結果ファイルにヘッダを付けたい場合は、どれか1つのファイルの1行目を付け足せばよいです。

````bash
cat *.csv | head -n 1 > result && find -name "*.csv" -exec sed -e '1d' {} \; >> result
````

または

````bash
cat *.csv | head -n 1 > result && find -name "*.csv" -exec tail -n +2 {} \; >> result
````

`head -n [N]`は、標準入力の先頭N行を出力します。

`&&`は、前のコマンドが正常終了ならば、後に続くコマンドを実行します。


以上です。誤り等ございましたらご指摘お願いします。
【Docker】Unsupported config option for services.app: 'node'

docker環境構築を作っていて、npmを初期化するコマンドを入力したら、Errorが発生した。

```
#docker-compose run --rm node npm init
ERROR: The Compose file './../docker-compose.yml' is invalid because:
Unsupported config option for services.app: 'node'
```

このError内容を見ると、docker-compose.ymlファイルの 'node' 辺りでErrorが発生しているみたい。。。

ymlファイルの該当箇所を確認したところ、本来は「services->node」が正しいが、「services->app->node」にインデントがずれていた。。。

間違い↓

```javascript
version: '3'
services:
  app:
    image: nginx:latest
    container_name: "app"
    ports:
      - "8080:80"
    volumes:
      - ./src/html:/app
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    node:
      image: node:10
      container_name: node
      tty: true
      working_dir: /usr/src/app
      volumes:
       - ./src:/usr/src/app
```

正しい↓

```javascript

version: '3'
services:
  app:
    image: nginx:latest
    container_name: "app"
    ports:
      - "8080:80"
    volumes:
      - ./src/html:/app
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
  node:
    image: node:10
    container_name: node
    tty: true
    working_dir: /usr/src/app
    volumes:
      - ./src:/usr/src/app
```

修正されたコードを実行したら

```
#docker-compose run --rm node npm init
Creating network "app_default" with the default driver
Pulling node (node:10)...
10: Pulling from library/node
0400ac8f7460: Pull complete
fa8559aa5ebb: Pull complete
da32bfbbc3ba: Pull complete
e1dc6725529d: Pull complete
572866ab72a6: Pull complete
63ee7d0b743d: Pull complete
90a199058c87: Pull complete
eec01b4217d9: Pull complete
a6a01f1bcd7b: Pull complete
Digest: sha256:9d06418fa4335f9cf96c59d5c09372f7a56329e7234456ee9fe2340c4ac35a95
Status: Downloaded newer image for node:10
Creating app_node_run ... done
```

無事成功！！！
【PowerShell】Wordの文書の文字をUnicode正規化する

## はじめに
Wordファイルに対して、Unicode正規化を実施するスクリプトのサンプル。

* Windows 10
* PowerShell v5.1
* Word のバージョンは Office 365

### 何があったか
あるとき、契約書の類いの文書に更新があり、差分をチェックする必要が出た。
提供された形式はpdfだったので、Wordへ変換し、タブ「校閲」→「比較」から比較を実施した。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424975/cf6f3991-26f8-317b-46b8-3d766d7e69ea.png)
すると、ぱっと見同じ文字なのに、変更ありとマークされている字がちらほら見つかった。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424975/ce49ad8b-95da-e24d-4392-99dc50e2c53d.png)
サクラエディタに該当箇所をコピペしてみると、文字コードが違うことが分かった。こっちだと、見た目が違うので分かりやすい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424975/02e3259a-4d32-201e-2eda-822c2b8b1d01.png)
原因としては、MacOSで文書を作成した場合、使用するアプリケーションによってUTF-8でも使うコードが違うことがある、というのが考えられるらしい。
対応方法としては、文書作成元へ問い合わせるのが一番だが、せっかくなので(？)コードでなんとかしてみた。

## サンプル
パラメータで指定されたdocxファイルを正規化する。
docxファイルはZip形式なので、それを解凍し、中にある`word\document.xml`ファイルを正規化して上書きする。
その後、圧縮しなおして新しいdocxファイルとする。

```powershell

Param($filePathDocx)

Add-Type -AssemblyName System.IO.Compression.FileSystem

# パラメータで指定されたファイルを正規化

# 拡張子チェック
if ($filePathDocx -eq $null -or -not $filePathDocx.EndsWith(".docx")) {
    Write-Host "[エラー] docxファイルではありません"
    return
}

# 正規化後ファイルパス
$filePathDocxOut = $filePathDocx.Replace(".docx", "_正規化.docx")

if (Test-Path $filePathDocxOut) {
    Remove-Item $filePathDocxOut
}

# docx解凍
$extractDir = [System.IO.Path]::GetTempPath() + "\word_extract_" + (Get-Date -Format yyyyMMddHHmmss)

[System.IO.Compression.ZipFile]::ExtractToDirectory($filePathDocx, $extractDir)

# document.xmlの正規化
$docFilePath = "${extractDir}\word\document.xml"
$tmpFilePath = [System.IO.Path]::GetTempFileName()

[System.IO.File]::Copy($docFilePath, $tmpFilePath, $true)

$reader = $null
try {
    $reader = New-Object System.IO.StreamReader($tmpFilePath)
    
    $writer = $null
    try {
        $writer = New-Object System.IO.StreamWriter($docFilePath, $false, [System.Text.Encoding]::UTF8)
        $line = $reader.ReadLine()

        while ($line -ne $null) {
            $line = $line.Normalize([System.Text.NormalizationForm]::FormKC)
            $writer.WriteLine($line)

            $line = $reader.ReadLine()
        }
        
    } finally {
        if ($writer -ne $null) {
            $writer.Close()
        }        
    }

} finally {
    if ($reader -ne $null) {
        $reader.Close()
    }
}

# 圧縮
[System.IO.Compression.ZipFile]::CreateFromDirectory($extractDir, $filePathDocxOut)

# 後片付け
[System.IO.Directory]::Delete($extractDir, $true)
[System.IO.File]::Delete($tmpFilePath )

Write-Host "done"
```
[基本情報技術者試験]うるう年の判定のアルゴリズムをPythonで書いてみた。

# 概要
- 基本情報技術者試験の午後の試験でアルゴリズムがあります。過去問を解いても理解ができません…。実際にアルゴリズムをPythonで書いて、理解を深めていきたいと思います。

- 前回は[ユークリッドの互除法](https://qiita.com/kuro_take/items/261e3d4cc2fd6a86147c)のアルゴリズムを書きました。
- 今回は**うるう年の判定**のアルゴリズムから書いてみます。

## うるう年の判定
#### アルゴリズム
  - 西暦が4で割り切れ、かつ、100で割り切れなければ、うるう年である。ただし、西暦が400で割り切れれば、うるう年である。どちらにも該当しないなら、うるう年ではない。

#### コード
```Python
# うるう年の判定を行うIsLeapYear関数
def IsLeapYear(Year):
    # 外側の分岐処理
    if Year % 4 == 0 and Year % 100 != 0: # この条件が真なら
        Ans = True # うるう年である
    else:
        # 内側の分岐処理
        if Year % 400 == 0: # この条件が真なら
            Ans = True # うるう年である
        else:
            Ans = False # うるう年ではない
    return Ans

print("実行結果：",IsLeapYear(2104))
print("実行結果：",IsLeapYear(2105))
print("実行結果：",IsLeapYear(2200))
print("実行結果：",IsLeapYear(2400))
```
#### 実行結果
```
実行結果： True
実行結果： False
実行結果： False
実行結果： True
```

# まとめ
- うるう年の判定って意外とややこしいんだなー
- 次回は**配列の最大値**をのアルゴリズムを書こうかな

# 参考
- こちらの本のCHAPTER3 02うるう年の判定を引用または参考にしました。
[情報処理教科書 基本情報技術者試験のアルゴリズム問題がちゃんと解ける本 第2版](https://www.shoeisha.co.jp/book/detail/9784798150468)
最新のシリアル番号を持つWondershare Data Recovery crack

<a href="https://jp.bitwar.net/howto/windows/2375.html">Wondershare data recovery crack</a>、Recoverit crack、シリアル番号、ライセンスキー、パス、アクティベーションコードを使用していますか? あなたは、コンピュータデータのさらなる損失を引き起こすリスクを取っている! 実際には、必要なデータを完全に取り戻すことができる無料のデータ復旧ソフトウェアがあります。

<B>Wondershare Data Recoveryクラックを取得</B>

既にコンピューターを慎重に操作し、データの損失は依然として発生します、これは避けられません。私たちはデータの損失に非常に怒っていますが、それを見つける機会はまだあります。


Wondershareデータリカバリは、画像、写真、ドキュメント、ビデオ、オーディオ、ハードドライブ、SDカード、USB外部ドライブなどからアーカイブファイルをリカバリするための強力なツールです。ただし、公式ウェブサイトからWondershareデータリカバリをダウンロードしようとしましたが、ソフトウェアが無料ではないことがわかりました。


次に、多くの人々は、シリアル番号、ライセンスキー、アクティベーションコード、または登録キーストアを含むWondershare Data Recovery CrackまたはRecoverit Crackを探すためにオンラインになります。実行不可能なプログラム、またはシステムのクラッシュ、ファイルの削除、クラックデータリカバリソフトウェアによる永久的なデータ損失などの結果が出ました。 それは本当に悪い経験でした。 しかし、これは私たちが聞いた最悪の状況ではなく、多くのユーザーは、Wondershare Data Recovery CrackまたはRecoverit Crackには常にウイルス、トロイの木馬、さらにはランサムウェア、マルウェアがバンドルされていると不満を述べています。恐ろしい。


それでは、なぜデータ復旧ツールの完全版をダウンロードするのではなく、時間を浪費して危険なデータ損失の状況に陥るのではなく、と考えていますか？


<B>100％無料のデータ復旧フリーウェアは、Wondershareデータ復旧クラックの最良の代替手段です</B>


現在のところ、必要かつ貴重なデータを取り戻すための実行可能なソリューションを見つけることが最も懸念される問題であるため、使いやすくウイルスのないデータ回復ソフトウェアが最良の選択です。ここでは、Bitwar Data Recoveryに頼ることができます。Wondershareデータリカバリと同様に、Bitwar Data Recoveryもデータ復旧フリーソフトウェアのフルバージョンです。 違いは、Bitwarが開発したソフトウェアは、著作権で保護されたデータリカバリソフトウェアであり、無料です。


とにかく、あなたは適切な場所に来ています。危険なソフトウェアを使用して記憶に残る写真、重要なドキュメントを永遠に失うリスクを誰も負いたくない。誤って不要なドキュメントを削除するなど、さまざまなデータ損失シナリオを処理するときにBitwar Data Recoveryは強力なヘルプを提供します。

日常生活には他にもさまざまなデータ損失状況がありますが、恐れることはありません。心配しないで、Bitwar Data Recoveryがあなたを助けます！次に、Bitwar Data Recoveryからデータを回復するためのステップバイステップガイドがあります。

   詳しくは、「<a href="https://jp.bitwar.net/howto/windows/2375.html">最新のシリアル番号を持つWondershare Data Recovery crack</a>」をご参照ください。
[Laravel] groupByが実行される前にidが新しいグループ順のデータを取得したい時に「whereIn」が使えた

## WhereIn 備忘録

whereInの使い方は、以下のwhereInを参照してください。
https://readouble.com/laravel/6.x/ja/queries.html
SQLのWHERE ~ IN ~ と同じ使い方なので大丈夫だとは思いますが、
SQLだと

```sql

SELECT *
FROM sports
WHERE name 
IN('baseball','football','basketball');
```
のように記述できるところを

```php
DB::table('sports')->whereIn('name', ['baseball', 'football', 'basketball']);
```
というように簡単に記述することができるのです。

本題ですが、
以下のようなテーブルがあり、question_idは別にquestionテーブルがあってリレーションしてる状態です。
question_idは1~3まであるとして、下のテーブルから
id = [4, 5, 6]のデータを取得したいのですが、
groupByを使用すると古い(idが若いもの id = [1,2,6])を取得してきてしまいます。

report テーブル

| id               |       question_id | 
|:-----------------|:------------------ |
| 1             |              2 |
| 2           |            1 |
| 3             |              1 |
| 4               |                1 |
| 5             |             2 |
| 6          |           3 |


そのため、以下のようなコードを実行するとうまくいきました。
reportのidカラム(whereIn第一引数)のなかで、
report question_idでグループ化されたレコードでreportのidが大きいもののリスト(whereIn第二引数)
のデータを取得する。

```php

DB::table('report')
    ->whereIn('report.id', function($query) {
        $query->select(DB::raw('MAX(report.id)'))
        ->from('report')
        ->groupBy('report.question_id');
    );

```

もっと他に良い書き方あるはずなんだろうけどとりあえず解決。
新google play consoleでのAndroidアプリ時間指定リリースの設定方法

google play consoleのUIがバージョンアップされ、時間指定リリースの方法がわからず、チャットにて問い合わせしたので備忘録です。

## チャットでの解答

> 公開の概要 > 青文字の「管理」　> 管理対象の公開をオン

で時間指定リリースの有効化ができるとのことでした。
（まだ、公式のドキュメントの更新は追いついておらず）

## せっかくなのでスクショ
![console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47244/80ace5cf-5fa1-361a-0dcc-cfbf451de709.png)


![公開の概要.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47244/a4236813-f9f9-b911-f3cb-c7b738afa0f9.png)

![公開の概要2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47244/1af9e88c-1adf-a557-7bde-3ff543b62399.png)


なお、旧式のコンソールと同様、一度アルファ版トラックなどで限定したテスターに公開しておけば、新規の製品版でも時間指定リリースが使えるという仕様は、これまで同様とのことでした。
(3)コマンドと処理量（O表記） - JS Algorithms and Data Structures Masterclass

個人メモです。


##データ単純処理における処理時間

| 処理 | 処理時間 |
|:-:|:-:|:-:|
| 挿入 (insertion)  | O(1) or O(n)  |
| 削除 (removal) | O(1)  or O(n) |
| 検索 (search) | O(n)  |
| アクセス (access) | O(1)  |
| object.keys | O(n)  |
| object.values | O(n)  |


アクセスはarr[0]のように、配列番号で指定したデータにアクセスすることをいう。配列の数に関係ない。

挿入と削除はどこに挿入、削除するかによる。
一番後ろの数値を削除する場合は、O(1)。ただ指定したデータを削除するだけ。

一番先頭を削除した場合、インデックス番号が振り直されるためO(n)となる。



<br>
##コマンド毎の処理量

| コマンド | 処理量 |
|:-:|:-:|
| push  | O(1)  |
| pop  |  O(1) |
| shift  | O(n)  |
| unshift  | O(n)  |
| concat  | O(n)  |
| slice  | O(n)  |
| splice  | O(n)  |
| sort  | O(n*long n)  |
| forEach  | O(n)  |
| map  | O(n)  |
| filter  | O(n)  |
| reduce  | O(n)  |

push, popはかなり早い処理。

concatは2つの配列を結合して新しい配列を作り出すため、要素の数だけ処理を繰り返す事になる。2n -> O(n)

```js:concat
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);

console.log(array3);
// expected output: Array ["a", "b", "c", "d", "e", "f"]
```

shiftやsliceなども配列の番号をごっそり変えることになるためO(n)となる。




<br>
##英単語
・tangible: 触れることができる

・the lens of: 〜を通して

・key-value pairs: オブジェクト

・constant time:　定数時間。O(1)。データ量に寄らず処理時間が一定

・intrinsic：本来備わっている

・misconception: 誤解

・blueprint: 設計図

・chronological:　年代順。history in order

・devise:　工夫する

・miraculous: 奇跡的な。ミラキュラス

・constaint:制約

・anagram: 言い換え。listen -> silent
Neural Network Console Challenge Audiostockの音声（BGM）データを解析

#はじめに
 [Neural Network Console Challenge](https://nnc-challenge.com/)(以下、NNC Challenge)というコンテストに参加しました。

#コンテスト概要
今回のNNC ChallengeはSonyが提供している [Neural Network Console](https://dl.sony.com/ja/)(以下、NNC)を用いて
[Audiostock]の音声（BGM）データを解析するというものです。
※学習用データ提供：[Audiostock]

コンテストに応募するとBGMデータと一覧表がダウンロードでき、学習に使用できます。
[Audiostock]:https://audiostock.jp/bgm

テーマは次の2テーマ
1.AudiostockのBGM検索の自動分類アルゴリズムを作り出す
2.自由な発想で音声データを解析する
例）似ている音声データをレコメンドするアルゴリズムを作り出す
　　曲の雰囲気に合うジャケット写真を自動生成する

#テーマ選択
今回チャレンジしたのは1の「AudiostockのBGM検索の自動分類アルゴリズムを作り出す」です。

#アノテーション(ラベル付け)
データに対してテーマに沿ったラベル付けを行います。
AudiostockのBGM検索の自動分類アルゴリズムということで、まずはHPの分類を確認しました。
HPを開くと幾つか選択可能でしたので、今回はイメージで分類をしてみることにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/0bc462ea-6a4f-93a3-c606-63bf187b32ec.png)
※[Audiostock] HPより

データと一緒にダウンロードした一覧のタグの列を元にDataSetを作成しました。
#### 一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/d4f18e3a-5221-f13e-6a6a-8908c7da8e65.png)

# DataSet
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/abe44a46-935c-c5ad-1751-2c39bcf90c33.png)

全部で48パターンあったので、正解ラベルはy0~y47とし、対応するラベルに1を、それ以外には0を付けました。
データの中には1つのBGMが複数のラベルに該当する場合もあり、その場合は該当するラベル全てに1を付けました。
例)「明るい」と「わくわく」など

DataSetをNNCで読み込むと、wavを直接指定することができます(ver.1.8から)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/6008c903-7c7a-315c-f1d1-292e91215d19.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/5d22db5d-bf36-7b4e-ea43-35fac8b6a5ef.png)

#モデル作成
NNCのサンプルにある「wav_Keyboard_sound」のプログラムをベースに作成しました。
それからYoutubeの[NNCチュートリアル：波形データの分類](https://youtu.be/-ZLTBpeBimE)を参考にしています。

データはサンプリング周波数8kHz、長さ24秒だったので、Inputのサイズは192,000になります。
8kHz × 24sec = 192,000

データを見ると、数秒ほどしか音声が無いデータなども含まれていたので、Sliceレイヤーを使用して1/3の8秒分のデータを抽出して学習に使用しました。
それから、今回の分類は複数ラベルへの分類になるので活性化関数はSoftmaxではなくSigmoidを使用しています。

モデルの簡単な説明です。
1.入力データからSliceを使用して8秒分のデータを抽出
2.MulScalarでデータ(波形の振幅)を-1~1の範囲に変換　※MulScalarのValueに1/32768を設定
3.Transposeで転置
4.Reshapeで画像データとして扱えるように次元を変換
5.ImageAugmentationでデータの水増し
6.Convolutionを繰り返す

##Main
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/325d19bc-a427-8f61-816e-fa50443a852f.png)

##ConvUnit
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/a9fbc0e8-1aa0-3bb1-8f6c-e0859d86ba3f.png)

#学習結果
**トレーニング結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/09721f17-d800-570e-c70e-71ce0c304555.png)
training error(赤の実線)、validation error(赤の破線)共に下がっていて、ほぼ0になるまでとはいきませんでしたが、まずまずでしょうか。

**評価結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411151/e55766db-b47a-3043-e9c1-fdb09cf50fc8.png)
続いて評価結果です。
Accuracy(正確度):0.1063
Precision(精度):0.0435
Recall(再現率):0.0431
トレーニング結果から、そこそこの数値を期待していたのですが、かなり悪い結果になりました。

#考察
評価結果が悪かった理由としては複数のラベルに分類されるデータが全問正解の場合に正解、1つでも間違えば不正解として評価されたのではないかと推測しました。
ただし、どうすれば結果が良くなるのかという解には至りませんでした。

#感想
1つのデータが複数ラベルに該当するような分類を行ったのは今回が初めてだったので、最初はどうすればいいのかさっぱりでした。
最初はvalidation errorが下がらず、データを見直したりしてようやく旨くいったと思ったら、評価結果はかなり悪く、そのままタイムアップという形となりました。
【Android / Kotlin】Bitmapのピクセル操作

Javaのコードはあったが、Kotlinはあまり無いようだったので、メモ

```Kotlin
fun Bitmap.filter(): Bitmap {
    val pixels = IntArray(width * height)
    getPixels(pixels, 0, width, 0, 0, width, height)

    for (y in 0 until height) {
        for (x in 0 until width) {
            //ここでピクセル操作（この場合は色反転を行っている）
            pixels[x + y * width] = pixels[x + y * width] xor 0x00ffffff
        }
    }

    return copy(Bitmap.Config.ARGB_8888, true).apply {
        setPixels(pixels, 0, width, 0, 0, width, height)
    }
}
```

関連記事

https://qiita.com/nakashimaakio/items/db37451c070550121644
【初心者向け】EC2でユーザーを登録してローカルからエイリアスで接続するまで

# 概要
　EC2でユーザーを登録する処理とローカルでsshのエイリアスを作成する方法をまとめます。
　久しぶりにサーバー立てるとつい手順を忘れちゃいますね。

# ゴール
1,ユーザーを作成する。
2,作成したユーザーに対して、（ローカルで） ssh <<任意の名前>>
　と打てばssh接続することができる。

# 手順
1,EC2にログインする。

```sh
$ ssh -i hogehoge.pem ec2-user@52.222.222.222 // Elastic IPにssh接続
```
2,ユーザーを作成して、コマンドの実行権限を付与(ルートユーザーの作成)

```sh
//　ユーザーを作成する 今回はtaroというユーザーを作成する。
$ sudo adduser taro

// ユーザーのパスワードを設定
$ sudo passwd taro
→パスワードを聞かれるので入力

// すべてのコマンドの権限を付与する
$ sudo visudo
→開いたら、 「root    ALL=(ALL)       ALL」 と記載してある場所を探し、
その下に 「taro    ALL=(ALL)       ALL」 を追加
```

3,ユーザーにsshの公開鍵を追加し、（ローカルで） ssh <<任意の名前>>
　と打てばssh接続することができるようにする。

```
// ユーザーを切り替える
$ sudo su - taro

//認証情報をユーザー配下に追加
$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ vim authorized_keys
→ファイルを開いたら公開鍵(id_rsa.pub的なやつ)の内容をペースト、作成方法は下に記載。
$ chmod 600 authorized_keys

これにてサーバー側完了。
この状態でも鍵は登録してあるので該当ユーザーでSSH接続は可能だが、
コマンドを短縮化して直感で扱えるようにローカルでエイリアスを作成する。
```

4,ユーザー側でエイリアスを作成する。

```sh
$ cd .ssh
$ vim config
→ファイルを開いたら以下の内容を追加
/*********************
Host <<任意の名前>>
  Hostname 52.222.222.222  // インスタンスのElastic IP
  Port 22
  User taro // サーバーで鍵を持つユーザー
  IdentityFile ~/.ssh/id_rsa // サーバーに登録した鍵とペアになる秘密鍵
*************************/

```
これで、ローカルで ssh <<任意の名前>>と打てば、接続できるはずです。



# 補足
公開鍵と秘密鍵の作りかた。

```sh
$　cd ~/.ssh
$　ssh-keygen -t rsa
```
これで作成されるもののうち、拡張子が.pubの方が公開鍵で、pubがない方が秘密鍵です。
例: id_rsa(秘密鍵) , id_rsa.pub(公開鍵)
Cognosのグラフで凡例を意図通りにソートするためのTips

Cognosでひとつのレポートに複数グラフを作成した時などに、それぞれのグラフの凡例の表示順番が揃っていないとデータアイテムごとの折れ線のカラーが揃わなかったりして、比較しにくいのでできれば揃えてほしい、というようなリクエストがあったりして、自分の意図通りの順番に凡例の表示をソートをしたいことがあります。
以下は、視覚化のタイプ「グラフ」を使ったグラフで使うことができる方法です。


例えば、以下のようなグラフを用意します。
このグラフの赤枠に囲まれている凡例を自由に並び替えたいとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/adc55bd3-1ce9-cd41-2deb-c5c1c6363a57.png)

まず、凡例に表示されるデータ系列はこちらです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/38b6c3f3-1e32-2347-d01e-8842f556f48a.png)

このデータアイテムを選択してソートを設定すればソートはできるのですが、このままだと、データアイテムの文字列でのソートになってしまいます。
そこで別途、各データアイテムの値ごとに任意の数値を割り振ったデータアイテムを追加します。

まず、sortitem1を追加します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/4f0763a2-2799-e7f5-6db6-b09db87c9388.png)

sortitem1には以下のようなcase文でそれぞれのデータアイテムごとの数値を指定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/f7e4a264-5701-ad55-6e94-9db9a5478cc0.png)

case文の指定が間違えていないかどうかは、クエリーアイテムの表形式で表示を利用することができるので、確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/9cb1128a-5ab2-9b98-049c-77109608c564.png)

以下が表形式データを表示の結果です。ちゃんと意図した通りの数値が割り振られているのが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/620e04d2-5668-9f4d-b03a-c125e3b05fe8.png)

それでは、グラフの編集画面で、データ系列を選択したままソートアイコンをクリックし、「レイアウトのソートの編集」をクリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/5ac117bd-c6aa-6c09-d435-b3a10b1ac2aa.png)

productLineのソートに使用するデータアイテムを指定します。
先程作成したsortitem1を右枠にドラッグして、降順にして、OKボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/14b7b27b-5f88-c11e-7951-8d1c579ed994.png)

ソートされた結果、以下のような並びに変わりました
一番上のグラフと比較してみてください。
４，outdoor Protection
３．Personal Accessories
２．Mountaineering Equipment
１．Golf Equipment
０．Camping Equipment
の順へ変わっていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/e57a4cd6-5d4c-b7b5-9bb7-ec0a2fcf91f0.png)

例えば、Mountaineering EquipmentとCamping Equipmentを上にしたいなと思った場合は、こんな感じで数値を変更して昇順にソートを設定すると・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/16442212-0676-83db-4b61-7b557e8e4a6b.png)
意図通りにソートすることができました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148873/2ff6a715-e86c-57bc-bfa6-77a4adb54b4d.png)

お役に立てば幸いです

以上
pybind11 + embed で sys.path にパスを追加する

## 背景

pybind11 embed(C++ 世界から python を呼ぶ)で自前のモジュール(.py)を読み込みたいので, パスを通したい.

PYTHONPATH 変数という手もありますが, 以下のようにしてパスを追加できます.

`sys.path` を一旦 `py::list` にキャストして, append します.


```
#include <pybind11/embed.h> // everything needed for embedding
namespace py = pybind11;

int main(int argc, char **argv)
{
  py::scoped_interpreter guard{}; // start the interpreter and keep it alive

  py::module sys = py::module::import("sys");
  py::cast<py::list>(sys.attr("path")).append("../");
  py::print(sys.attr("path"));
}
```
OpenImageDenoise の実装メモ

https://www.openimagedenoise.org/

* oneDNN(mkl-dnn)が必須です.
  * oneDNN を使って推論を実行しているため 
* TBB が必須です.
* ISPC が必須です(一部フィルタなどの処理が ispc で記述されているため
* ソースコード自体は実質 x86 限定です.
  * ispc, TBB など arm64 ビルドが面倒なため. 
  * Blender でも OIDN だけ arm64 対応はまだ https://developer.blender.org/D8236

## ネットワークモデル

ネットワークは encoder/decoder モデルです.

ネットワークレイヤーは Conv2d, Pool2d, Upsample, Concat しか利用していません.

`training` フォルダに, pytorch でのモデル定義がありますのでそちらを参考にしましょう.

## weight データ

TZA(Tensor Archive)であります. 特に複雑なものではないです.
パースはこちら.

https://github.com/OpenImageDenoise/oidn/blob/master/common/tza.cpp

oidn では, ビルド時に一度 python で .tza ファイルを .cpp に変換してライブラリに埋め込むようになっています.
(ので .cpp が巨大). 

データのレイアウトは文字列であります. `"oihw"` など(ML 系の記法なので, あとのほうがメモリ上の次元が小さい)


## 実行

unet.cpp でネットワークのビルドと実行をしています.

https://github.com/OpenImageDenoise/oidn/blob/master/core/unet.cpp

処理の効率化を図るため, oneDNN の blocked layout でタイルで処理するようにしています.

https://oneapi-src.github.io/oneDNN/dev_guide_understanding_memory_formats.html

画像のタイル化のために, input_reorder, output_reorder が用意されています.

データのレイアウトは `NCHW`(pytorch 系)となっています(のはず)
単純がゆえにrootで叩くと痛い目を見るコマンド集（体験談）

# はじめに
今まで本番環境でやらかしてしまったrootコマンドを晒して、同じ地雷を踏まないようにしたいと思い、列挙しました。

# 私こんなことやらかしました

| やらかしたコマンド | やりたかったこと | 結果 | 今後の展望 |
|:-----------|------------|------------|-------|
| last &#x7C; reboot | 直近の再起動時刻を知ろうとして | 無事今が直近の再起動時刻になりました | uptimeを使いましょう。。。 |
| hostname -a | マシンのFQDNを知ろうとして | FQDNが無事`-a`になりました | uname -aでいいです。。。 |
| rm -rf /tmp/test / | `/tmp/test/` ディレクトリを全消ししようとして | システムを全消しします | 余計な`/`はつけるのやめましょう。。。スペース一つで全て終わる。 |

# まとめ
以上のコマンドをforやらwhileと組み合わせると絶望感がやばいです。何度`Ctrl-C`を叩いたか。
他にもたくさんやらかしコマンドあると思うので、同じ地雷を踏まないようにもコメントでシェアしてもらえると嬉しいです。

# その他にも良い子は真似しちゃいけないコマンドが色々と
国を超えてやらかす人はやらかすんだなぁ。

- https://www.howtogeek.com/125157/8-deadly-commands-you-should-never-run-on-linux/
- https://vitux.com/10-deadly-commands-that-you-should-never-run-on-linux/
PHP 一覧表示機能、fetch+whileをfetchAll+foreachに書き換える。

## fetch+while

fetchは一件だけ取得するとそこで処理が終わる。whileでそれを繰り返すことで一覧表示できる。

```php
while ($user = $users->fetch(PDO::FETCH_ASSOC)) : ?>
   <div class="msg">
    <img src="<?php print(htmlspecialchars($user['picture'])); ?>" />
    <p><span class="name"><?php print(htmlspecialchars($user['title'])); ?>です</span></p>
   </div>
<?php endwhile; ?>
```

## fetchAll+foreach

fetchAllでデータを全件取得してそれを配列にまとめるので、その配列化したものをforeachで１件ずつ表示する。

```php
$users = $users->fetchAll(PDO::FETCH_ASSOC);
  foreach ($users as $user) : ?>
   <img src="<?php print(htmlspecialchars($user['picture'])); ?>" />
   <p><span class="name"><?php print(htmlspecialchars($user['title'])); ?>です</span></p>
   <br>
<?php endforeach ?>

```
Rails 新規アプリケーション作成の基本

#新規アプリケーション作成の基本

今回はruby on railsで新規アプリケーションを立ち上げる際の基本をまとめておこうと思います。

前提としてrailsのバージョンは6.0.0でデータベースはMySQLというツールを用います。

##新規アプリの準備

```
#　ディレクトリの移動
% cd ~/アプリを作成したいディレクトリ名

# 新規アプリを作成(chochikuというアプリ名)、-dオプションでMySQLの使用を明示して作成
% rails _6.0.0_ new chochiku -d mysql

# 作成したchochikuのディレクトリに移動
% cd chochiku
```

以上のコードをターミナルに打つことで新規アプリケーションが立ち上がります。

##データベースの作成

コマンドを利用してアプリのデータベースを作成しますが、その前にデータベースに関する設定を少しする必要があります。

データベースに関する設定はdatabase.ymlに記述します。

database.ymlのdefaultの下のencoding: utf8mb4という記述を
encoding: utf8に変更します

そして以下のコマンドを実行すればデータベースの作成を行います
※必ず自分の作るアプリのディレクトリでコマンドを実行してください！

```
% rails db:create
```

##モデルの作成

railsのアプリケーションにはデータベースとやりとりをするモデルが必要になります。

```

#　Expenseモデルを作成
% rails g model expense
```

##テーブルの作成

###マイグレーションファイルの編集

上記のモデルを作成した時、同時にマイグレーションファイルがdb/migrateというディレクトリに生成されます。
このマイグレーションファイルを編集してテーブルに保存する情報を決定します。

```
class CreateExpenses < ActiveRecord::Migration[6.0]
  def change
    create_table :expenses do |t|
      t.string :name
      t.integer :shuppi
      t.timestamps
    end
  end
end
```

例えばt.string :nameというコードはstring型でnameというカラムをテーブルに追加しているということです。

###マイグレーションの実行

マイグレーションファイルを編集しただけではテーブルについて変更を加えたことにはなりません。そこでマイグレーションの実行をする必要があります。
以下のコマンドを実行することでマイグレーションを実行することができます。

```
% rails db:migrate
```

##まとめ

以上でアプリの一つのモデルとそのモデルに紐づくテーブルを作ることができました。
実際にはこれからこのモデルに紐づくコントローラーやルーティング、ビューを作っていくことでアプリを作ることになります。
新規アプリ作成の基本としてはとりあえずここまでですm
Dockerとdocker-composeを ラズパイ4 と Linux(Debian) と Windows10 にそれぞれインストールする

最近勉強している、Docker と docker-compoesについて書きます。
本当は、同じDockerfile と ymlを用いて動作環境を作って便利さを実感するところまで書きたかったのですが、次回にしようと思います。

## まず、ラズパイ4にDockerとdocker-composeをインストール
ラズパイはARMだからか？、Linux版とはインストール方法が異なる。

### 環境
- ラズパイ4 + Rasbian10

### 1.前準備
#### 1-1. パッケージの一覧を更新する
<pre>
$ sudo apt-get update
</pre>

#### 1-2. gitインストール  
<pre>
$ sudo apt-get install git-all
</pre>

#### 1-3. curlインストール
<pre>
$ sudo apt-get install curl
</pre>

### 2. Docker/docker-composeインストール
#### 2-1. Dockerを取得しインストールする。
<pre>
$ curl -sSL https://get.docker.com | sh
$ docker -v
Docker version 19.03.13, build 4484c46d9d
</pre>
versionが表示されれば、インストール成功。

### 2-2. Docker composeインストール

gitから取得した環境docker-compose instal shellを実行

<pre>
$ git clone https://github.com/docker/compose.git
$ cd compose
$ git checkout 1.27.4
$ sudo ./script/build/linux
$ cd dist
$ sudo cp docker-compose-Linux-armv7l /usr/local/bin/docker-compose
$ cd /usr/local/bin
$ sudo chown root:root docker-compose
$ sudo chmod 755 docker-compose
$ docker-compose -v
docker-compose version 1.27.4, build 40524192
</pre>
versionが表示されれば、インストール成功。

## 次、PC LinuxにDockerとdocker-composeをインストール

### 環境
- Debian10

### 1.前準備
ここはラズパイと同じため、省略

### 2. Docker/docker-composeインストール
#### 2-1. Dockerを取得しインストールする。
<pre>
$sudo apt-get -y remove docker docker-engine docker.io
$sudo apt-get -y update
$sudo apt-get -y install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg2 \
    software-properties-common
$sudo curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -
$sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
   $(lsb_release -cs) \
   stable"
$sudo apt-get update
$sudo apt-get -y install docker-ce
$docker -v
Docker version 19.03.13, build 4484c46d9d
</pre>
versionが表示されれば、インストール成功。

### 2-2. Docker composeインストール

gitから取得した環境docker-compose instal shellを実行

<pre>
$sudo curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
docker-compose version 1.27.4, build 40524192
</pre>
versionが表示されれば、インストール成功。

## 最後、Windows10
ほぼ、手動でやることはなかったので、ほぼ参照です。。

## 環境
- Windows10 + WSL2  
※最終的に、VSCodeと連携するおデバッグ実行できてとても便利。

### 1.前準備
#### 1-1. Windowのバージョンを2004以降にする。
下記参照。
https://support.microsoft.com/ja-jp/help/4028685/windows-10-get-the-update

#### 1-2. WSL2をインストールする。  
下記参照。
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10  

### 2.Docker DeskTopをインストール(Windows向けDocker、docker-compose環境) 
#### 2-.1 Docker DeskTopインストール 
下記参照。
https://docs.docker.com/docker-for-windows/install/

次回は、Dockerfile、ymlファイルを用意して実行するところを書きます。
remote.it DesktopApp (Windows)のインストール

# 1. 今回の要約
* remote.it DesktopApp (Windows)をインストールする

remote.itによるリモート接続を行うためには、次のいずれかの方法があります。

1. remote.itポータルサイトからの接続を行う
1. remote.it DesktopAppからの接続を行う
1. remote.it CLI / connetd / Web API からの接続を行う

OSがWindowsやMacOSなどの場合には、GUIから使用できるDesktopAppの利用が便利です。本稿では、WindowsへのDesktopAppのインストール方法を説明します。

# 2. remote.it DesktopApp (Windows)のインストール
* ブラウザより、remote.itのWEBサイト([https://remote.it/](https://remote.it/))を表示します。続いて、上のDownloadsを選択します。
<img width="50%" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771955/d2d812b3-866f-5698-e71a-18f2e62c52dd.png">

* Desktop Applicationsより、Windows用のインストーラ(remote.it for Windows (32/64 bit))をダウンロードします。
<img width="50%" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771955/d764c5a7-deec-8ea8-1afb-01ebe6e5d169.png">

* ダウンロードしたインストーラを実行します。必要に応じて任意のインストール先フォルダを入力し、インストールを押下します。
<img width="50%" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771955/4375d201-ea4e-afbe-9db7-aff9aef8091b.png">

* インストールが完了した後に、完了を押下します。
<img width="50%" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771955/bc226a82-7617-c062-35c8-c1fb173ceeed.png">

* remote.itアプリケーションが実行されるので、remote.itアカウント(WEBサイトより取得ください)のメールアドレスとパスワードを入力した後に、SIGN INを選択します。
<img width="50%" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771955/b9f54dea-f324-bb9c-dfba-f3817f04d02e.png">

* ログインに成功すると、デバイス一覧が表示されます。まだデバイスが登録(もしくは共有)されていない場合には、何も表示されません。
※再度remote.itアプリケーションを使用する場合には、タスクトレイから実行できます
<img width="50%" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771955/a356d5cc-2ddc-17ad-7717-8f87e0318dd7.png">
Python で parameter store を使う

# はじめに

以前、仕事で使った Parameter Store（AWS Systems Manager） をまた使うことになったので思い出しました。

今回も[Poetry + Docker](https://qiita.com/va034600/items/dde20a965e212ab449b2)を開発環境にしています。
ソースは [Github](https://github.com/va034600/python-parameter-store) にあげてあります。

# Parameter Store を設定する
`/aaa` で始まるように作成
![スクリーンショット 2020-10-19 16.58.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203946/6d265d67-b1f3-66e2-204f-f507fdad2ebe.png)

# ファイル
mainとライブラリとしてファイルを分けています。

```python:main.py

from src.ssm_manager import SsmManager

print("start")

ssm_manager = SsmManager(region_name="ap-northeast-1")
ssm_manager.load_parameter(base_ssm_path="/aaa")
print(ssm_manager.parameters)
```

```python:ssm_manager.py
from typing import List, Dict

import boto3


class SsmManager:
    def __init__(self, region_name: str):
        self.__ssm = boto3.client('ssm', region_name=region_name)
        self.__parameters = []
        self.__base_ssm_path = None

    @property
    def parameters(self) -> List[Dict[str, any]]:
        return [{
            'name': item['Name'].replace(f'{self.__base_ssm_path}/', ''),
            'value': item['Value']
        } for item in self.__parameters]

    def load_parameter(self, base_ssm_path: str) -> None:
        self.__base_ssm_path = base_ssm_path
        result = []
        next_token = None
        while True:
            dict_parameter = {
                'Path': base_ssm_path,
                'Recursive': True,
                'WithDecryption': True,
            }
            if next_token is not None:
                dict_parameter['NextToken'] = next_token
            response = self.__ssm.get_parameters_by_path(**dict_parameter)
            parameters = response['Parameters']
            result.extend(parameters)
            if 'NextToken' not in response:
                break
            next_token = response['NextToken']
        self.__parameters = result
```


# 終わりに

これで、環境変数などに入れていたRDSのパスワードなどを保存できます。
ゲームを作りながら学ぶ！JavaScript レベルアップ講座 part4

こんにちは、[Yui](https://twitter.com/yui_active)です。

今回はcanvasを使って背景やモンスターを描画する方法について書いていきます。
JavaScript道場は[こちら](https://x-hack.connpass.com/event/196255/?utm_campaign=event_publish_to_series_watcher&utm_source=notifications&utm_medium=email&utm_content=detail_btn)。

今回の目標物はこれです。
![スクリーンショット 2020-10-19 17.11.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670446/573d9a23-4ab3-cb57-33ab-a9ef9b95ac32.png)


#canvasとは？

canvasとは、HTML5に標準装備されている図形を描くための技術仕様で、 HTMLの``<canvas>``要素とJavaScriptを組み合わせて図形を描画することができます。

公式ドキュメントはこちら。=>https://developer.mozilla.org/ja/docs/Web/HTML/Element/canvas

ざっくりというと、canvasを使うことで、画像の描画やアニメーション、ゲームのグラフィック、データの可視化、写真加工などを簡単に描画することができます。

canvasは基本的には2Dでの画像表示を対象としています。

#使い方
まずはcanvasをbodyタグに組み込む必要があります。

```html
<canvas id="canvas" width="640" height="480" style="background-color: black;"></canvas>
```

そして上記で指定したidを使って、``<script>``内に組み込みます。

```javascript

<script>
  const canvas = document.getElementById("canvas")
  const ctx = canvas.getContext("2d")
  const img = new Image()
  img.src = "画像のURL"
  img.onload = () => ctx.drawImage(img, 0, 0, 100, 100)
</script>
```

順番に解説します。

まず、今回canvasのidは``canvas``で指定しました。
なので、``document.getElementById``を使って``canvas``というidの部分にJavaScriptを結びつける必要があります。

そして次の``const ctx = canvas.getContext("2d")``はcanvasを2dの画像描画に適用させるということです。ここで**ctx**と変数に格納したので、それ以降は**ctx.hogehoge**という形でcanvasの機能を使うことができます。
canvasという設計図の中に入っているhogehogeという機能にアクセスをすることができるわけです。

canvasでは画像を描画する際には``drawImage(描画させる画像, x軸, y軸, 横幅, 縦幅)``で表すことができるので、ここでは``ctx.drawImage(img, 0, 0, 100, 100)``と書くことで、横幅100、縦幅100のimgという画像を(0,0)の位置に表示することができます。

# 実際にスライムを表示させてみる

実際にスライムを表示させてみましょう。

スライムの画像は以下のURLから用います。
https://cache-www.dragonquest.jp/hoshidora/assets_190310/narikirislime/pc/slime.png

まずは基本となるHTMLの雛形

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
</body>
</html>
```

``body``内にcanvas部分を記載

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <canvas id="canvas" width="640" height="480" style="background-color: black;"></canvas>
  <script>
    const canvas = document.getElementById("canvas")
    const ctx = canvas.getContext("2d")
    const img = new Image()
    img.src = "https://cache-www.dragonquest.jp/hoshidora/assets_190310/narikirislime/pc/slime.png"
    img.onload = () => ctx.drawImage(img, 0, 0, 100, 100)
  </script>
</body>
</html>
```

これで無事スライムが表示されたかと思います！

もしもっと学びたいという方はぜひ[JavaScript道場](https://x-hack.connpass.com/event/196255/?utm_campaign=event_publish_to_series_watcher&utm_source=notifications&utm_medium=email&utm_content=detail_btn)にご参加ください。
次回はこれを使ってスライムを動かしていきます。
【Windows】Windows Update 実行コマンド

## Windows Update 実施コマンド

##### 検証環境
　・windows 10

##### UsoClient.exe
　・Windowsのタスクスケジューラで実行されているWindowsUpdateに関するコマンド
　・wuauctlはWindows10から廃止されUsoClient.exeを利用
　 参考：[MicrosoftDoc](https://docs.microsoft.com/ja-jp/archive/blogs/yongrhee/wuauclt-detectnow-in-windows-10-and-windows-server-2016)

##### Windows10での利用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602028/957642c0-5f42-ad5e-1fd5-9cd02daf72b1.png)

##### 主なコマンドオプション
|コマンド|オプション|説明|
|---|---|---|
|UsoClient|StartScan|更新プログラムをチェック|
|UsoClient|StartInstall|更新プログラムをインストール<br>※手動で「インストール」ボタンを押下しないといけないプログラムはインストールできない|
|UsoClient|StartInteractiveScan|Windows Update画面のボタンをクリック<br>※手動でボタンを押下した動き|

参考：https://omgdebugging.com/2017/10/09/command-line-equivalent-of-wuauclt-in-windows-10-windows-server-2016/
　

## 使用例

```console
C:\Windows\System32\UsoClient.exe startscan
C:\Windows\System32\UsoClient.exe StartInstall
C:\Windows\System32\UsoClient.exe StartInteractiveScan
```
正規表現で「先頭ではない」「行末ではない」を表現

# やりたいこと
**先頭ではない|**を置換したい。
Markdownの表をHTMLに変えたかった。
[Markdown表変換ツール - MarkDown Convert](https://markdown-convert.com/ja/tool/table)を使うという手もあります。

# 正規表現
参考 : [正規表現で、「先頭にある」文字列ではなく、「先頭にはない」文字列だけにマッチさせたい場合 - Sakura scope](https://www.nishishi.com/blog/2013/02/regexp_not_head.html)

```bash
(.)\|(.)
```

## 考え方
否定を考えるのではなく`^\|`(先頭の|)じゃなくて直前に任意の1文字`.`がある`\|`と考える。
`.\|.`ではなく`(.)\|(.)`とするのは直前にある任意の1文字`.`を置換後の文字で`\1` `\2`として削除されないようにする。
`hoge|fuga`を`hoge</td><td>fuga`にしたくて`.\|.`で置換後文字を`</td><td>`にすると`hog</td><td>uga`になって、`.`に相当する`g`と`f`が削除される。


## 例

```markdown:置換前
|head1|head2|head3|
|:-:|:-:|:-:|
|hoge|fuga|poo|
|hoge|fuga|poo|
|hoge|fuga|poo|
```

|置換対象|置換後|
|:-:|:-:|
|(.)&#092;&#124;(.)|\1&lt;/td>&lt;td>\2|


```http:変換後
|head1</td><td>head2</td><td>head3|
|:-:</td><td>:-:</td><td>:-:|
|hoge</td><td>fuga</td><td>poo|
|hoge</td><td>fuga</td><td>poo|
|hoge</td><td>fuga</td><td>poo|
```
ssh keyの登録方法

https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent

```
tsuboi@tsuboi hotel-project-spring % ssh-keygen -t rsa -b 4096 -C "igarage@gmail.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/tsuboi/.ssh/id_rsa): <このままEnter>
Enter passphrase (empty for no passphrase): <このままEnter>
Enter same passphrase again: <このままEnter>
Your identification has been saved in /Users/tsuboi/.ssh/sample_igarage.
Your public key has been saved in /Users/tsuboi/.ssh/sample_igarage.pub.
The key fingerprint is:
SHA256:EDfM107HohOoo7eFhArJne1rk3FgaJh0sW6IxKWtkoQ igarage@gmail.com
The key's randomart image is:
+---[RSA 4096]----+
|   o. .oo. . .   |
|o.+..  o+.o + o  |
|E*=o+... . = o   |
|*=+=.++.  o .    |
|++.+oo.oS  .     |
|. o .oo..        |
|     .=o         |
|     =.          |
|    . .          |
+----[SHA256]-----+
tsuboi@tsuboi hotel-project-spring % ls ~/.ssh/
id_rsa.pub id_rsa
tsuboi@tsuboi hotel-project-spring % cat ~/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDLYXb92jzvmZIXwSIzJD0fuPuDf10nYAOGfpMBn8qN7sPoTw17sU46mWMwT/bbkFyfxP4FRsNZbFl7lIATYFk8lY3BRqfnjxlaATqAo4F5U2l28WGJyqStrky9U3jrYum9NTd4uSzoDwTnh2PE+PeT9bEl0KguRCttUot9C8u2zMIShx7bYc+3cbtT8Ix0M7nP0VGCyXBe7RZanFew/JcGiNVL3MEx0ygZ1d/wlBfXJAF+8egod2SWAthARo+pmJ0n/s1TGtHFY7jwLVbnjXdKVSOf9cq0t0qu5v9RuWuznCkKNfk1S7bW9P2qUjXZNkT7KqmAnm04tyDj7Q3g7KCR1oxzpgWw3yj/L+JwOBn8miCEtMSmD8RJ0AqEcOKgF8Bb8kOLqACU0NbQUEhtDz8272tTcp8cg4UXUTlHLyVskTVtkzlEw59ksuxMZvAwxkhdjtRRbqlQKI7SfycrEB83+hYA1Fa/GexAFBzhiKgiIuLSHxyujodKIsTXrWprdVlR0CJFjatPWD4vDyVXm6oFX32O4SgftAhJ1aCjP3APXYeUKQlzu4iky15Mxo8etqEbw9Jct1YLh73cPqLSimOf1J95zE4mASPRpOC1TQwJcQJBxJJR/vtSV2AyDvk6nRSH2C5LRFcxdSkajYEYidd5tKo2csiHGw/wcJllXXK1bQ== igrage@gmail.com
```
hover時のCSS無効、CSSでHTMLの要素の順番を変える、疑似クラス

最近使ったCSSやjQueryの技:sparkles:をまとめます。その１

#お品書き

+ hove時のCSSを無効にする・・・`pointer-events: none;`
+ 要素の順番をCSSで入れ替える・・・`flexbox `
+ クラスの何番目の要素で指定・・・疑似クラス`:nth-child()`

#hove時のCSSを無効にする
以前、checkboxの値に応じてボタンの有効無効を切り替える記事を書いたのですが、
:point_down_tone2::point_down_tone2::point_down_tone2:
[jQuery　checkboxに応じて切り替え](https://qiita.com/aliceroot0678/items/4a6eaba745afd3fb3553) 　:qiita:
 
もともとボタンをhoverしたときにボタンの色が濃くなるなどのCSSはそのまま適用されてしまうので、利用する側からは押している感覚（といって正しいのか）があるのに、ページが進まないのは変だよね。

ということで、hover時のCSSを無効にする方法を調べた。:runner_tone3::runner_tone3::runner_tone3:
ボタンに`disabled`属性をつけたり外したりしてボタンの有効無効を変えていたので、
CSSも同じ要領でやる？と考えたんですが、もっとお気軽な方法が！

```css:css
button[disabled] {
    pointer-events: none;
}
```
なんて簡単！:heart_eyes: :heart_eyes: :heart_eyes:
`pointer-events`は初期値では`auto`で、
`none`にすることでその要素がポインターイベントの対象にならなくなる。

#要素の順番をCSSで入れ替える
HTMLは変更せずにCSSだけで要素の順番を変えたい！
##`flexbox`を使う

```html:html

<div class="main">
  <ul>
　　<li class="text">22222</li>
　　<li class="text">33333</li>
　　<li class="text">11111</li>
　　<div>
  </ul>
</div>
```
上記のコードでは数字が2→3→1になってしまうので、正しい順番に表示したい。
ただ、HTMLの順番を変えるのではなく、CSSで順番を変える。（たとえば、PCとスマホバージョンで表示の順番を変えるときとかに使う）
このときに使うのが`frexbox`
##Flexboxの使い方
親要素にcssで`display:flexbox;`を追加。
これを追加することで、親要素をFlexコンテナーに設定。
Flexコンテナーに含まれる子要素をFlexアイテムとして設定される。
さらに、`flex-direction`で並び方をいじれる。初期値はrow。縦（公式的には積み重なるように）にしたかったので今回はcolumnで指定。

```css:css
main {	
	display:flex;
        flex-direction:column;
}
```

さらに、子要素に`order:順番を示す数字;`を設定することで表示させる順序を入れ替える事ができる。
・・・今回はここで問題発生
子要素のクラスが3つとも`text`なので、指定するにはどうすれば？:joy:
**擬似クラス**という便利なものがあるそうで。それを使ってみる。

```css:css
.text:nth-child(1){
    order:2
}
.text:nth-child(2){
    order:3
}
.text:nth-child(3){
    order:1
}

```
これで、textクラスの表示の順番を変えることができた。
ちなみに、孫要素には効かないらしいので注意。:point_up_tone2::point_up_tone2::point_up_tone2:

#擬似クラス
さっき使った擬似クラスについて。

```
対象となる要素：nth-child(n)
```
これで、対象となる要素の中でn番目の要素を指定することができる。クラスを増やすまでではないときに使うと良さそう。
ちなみに、`()`の中身は2nとかで偶数番目だけとかで色々条件指定ができるそう。
細かく見たいときは[こちら]((http://www.dolceproof.jp/topic/reference/referencecss/nth-childn))を。（下の方に参考にしたサイト全部のせてます）




#参考にしたサイト
[pointer-eventsプロパティですごい便利に！クリックやホバーのターゲットになる要素を変更するテクニック](https://coliss.com/articles/build-websites/operation/css/css-pointer-events.html)
[【Flexbox】HTMLの記述を変えずに表示順を変えるCSS](https://web-yaro.net/css/131/#html)
[要素の順番を入れ替えられるflexboxのorderを活用しよう](https://www.attend.jp/html_171101)
[CSS公式-flex-direction-](https://developer.mozilla.org/ja/docs/Web/CSS/flex-direction)
[E:nth-child(n) 疑似クラス《前からn番目、一定間隔おきに指定》-CSS-](http://www.dolceproof.jp/topic/reference/referencecss/nth-childn)
参加者リスト自動作成システムを作ってみた

会社内で社員向けのイベントを開催する機会があり、参加者の集計を簡単にするため、社員証をかざすと参加者リストに反映されるシステムをenebularで作ってみました。

概要は以下のブログに書いてあります。
[enebularブログ　社員証タッチで参加者リストを自動作成](https://blog.enebular.com/samples/iccard2spreadsheet/)

このページでは、セットアップ手順について説明します。

ブログにもちょっと書いていますが、H/W的には以下の構成で作っています。

* Raspberry Pi 3B+（OS：[raspbian-buster-2019-09-30](https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-09-30/)、アプリ：[enebular-agent 2.15.0](https://docs.enebular.com/ja/EnebularAgent/Overview.html)  AWS IoTコネクション）
* ソニー 非接触ICカードリーダー/ライター PaSoRi RC-S380（USBでRaspberry Piに接続）
* ブザー（電圧を加えるだけで鳴るもの　Raspberry piのP5に接続）

# セットアップ手順
フローはenebularのDiscoverでパブリッシュしています。

[https://enebular.com/discover/flow/53d7c390-9a5f-47fc-8d0f-ebc4655670a6](https://enebular.com/discover/flow/53d7c390-9a5f-47fc-8d0f-ebc4655670a6)

フローのデプロイ以外にもPaSoRiを使えるようにする手順とGoogleスプレットシートに書き込むための手順がありますので、紹介します。

## nfcpyをインストール
PaSoRiからはnfcpy-id-readerというPyhtonスクリプトを介して、カードの情報を受け取ります。そのセットアップ手順は次の通りになっています。

1.追加python環境のインストール

```shell
$ sudo apt-get install python-usb python-pip -y
```

2.pythonライブラリのインストール

```shell
$ sudo pip install -U nfcpy-id-reader
```

3.ユーザー権限でもPaSoRiにアクセス可能にする

```shell
$ cat << EOF | sudo tee /etc/udev/rules.d/nfcdev.rules
SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06c3", GROUP="plugdev"
EOF
```

4.再起動

```shell
$ sudo reboot
```

## スプレットシートの設定

フローの中ではスプレットシートに書き込むためのノードを使用しています。スプレットシートに書き込むためにはいくつか設定が必要です。以下のブログを参考にしてください。

[enebular-Blog Google スプレッドシート・ノードを使おう](https://blog.enebular.com/nodes/letsuse-google-spreadsheet-node/)

フローでは、A列に番号、B列に日時、C列にIDを書き込みます。
IDから名前や個人情報をリスト表示するのはスプレットシート側で行っています。

# まだまだなところ
今回のフローはざっと数時間でプロトタイピング的に作ったものです。まだまだ課題があります。

* 連続して同じIDはスプレットシートに書き込まれないようになってるが、間に異なるIDを挿むと書き込まれてしまう
* スプレットシートの切り替えがフローを変更しないとできない
* インストールが手間

上記のいくつかはenebularの有償機能である[ファイルデプロイ機能](https://docs.enebular.com/ja/Files/Introduction.html)を使えば解決できそうなので、チャレンジしてみます。
Next.js初期インストール時にエラーが発生する人向け対処法

自分が詰まりかけたため、同じような状態になってしまった方を対象にして回避方法を記入しておきます。

この問題はnpx create-next-app を実行した際に、
npm ERR! code ENOLOCAL
npm ERR! Could not install from "xxx\AppData\Roaming\npm-cache\_npx\14184" as it does not contain a package.json file.

のような記述が返ってきてインストールできない人向けのものです。

この問題は使用者のユーザー名の中にスペースがあるのが原因です。
例えば私の場合ですと、苗字と名前の間にスペースが存在するため、このエラーが発生してしまいました。（修正してくれ…）

対処法ですが、インストールしたいフォルダーの所へ行って
 npm config set cache "c:\tmp\nodejs\npm-cache --global"

を実行してください。「npm-cache」フォルダーが別のパスに変更されるので、これで回避可能のはずです。
【AWS】Mysql2::Error::ConnectionError: Access denied for user 'root'@'localhost' (using password: YES)を解決した話

こんにちは、あおい（https://twitter.com/aoi_engineer ）です。
今回はAWSでローカル環境で作ったアプリをデプロイしているところでエラーが起きました。

詳しくは以下の通り。

<h2>実行</h2>

```
$ rails db:create RAILS_ENV=production
```

<h2>エラー内容</h2>
```
Mysql2::Error::ConnectionError: Access denied for user 'root'@'localhost' (using password: YES)
```

こんな感じでエラーが起きました。

結論、僕の場合はパスワードが一致していませんでした。

<h2>解決方法</h2>

```
$ env | grep DATABASE_PASSWORD
```
で返ってくるパスワードと、

```
$ mysql -u root -p
```

で実行するパスワードが一致していませんでした。

なので、

```
$ sudo vim /etc/environment
```

を実行してパスワードを変更しました。

そして、その後に実行すれば

```
$ rails db:create RAILS_ENV=production
Created database 'furima_30440_production'
```

このように返ってきました！
解決！
Zabbix4.0 のグラフ画面で豆腐文字(文字化け)してしまう問題を解決してみた

# 事象内容
Zabbix4.0のグラフ画面を確認したら、□□□のような豆腐文字(文字化け)があった
![WS_2020_1019_000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518227/f614bbf3-dc45-4272-887d-521efc62f035.jpeg)

# 原因
以下の2点が原因だった
1. Zabbixのダッシュボードの言語を日本語に設定した
⇒英語に設定すれば文字化け自体は回避可能
2. 日本語に設定した際、日本語に対応したフォントを設定していなかったため、対応していない部分が文字化けした

# 対応方法
今回は原因2の対応を行い、日本語設定したまま文字化けを解消した。
※この記事にコメントをしてくれた方が下記手順よりスマートな方法を教えていただきました。
　手順は下部に追記いたしましたのでこちらもご参照ください。

```java:
[root@zabbix-master ~]# ls -l /etc/alternatives/zabbix-web-font
lrwxrwxrwx 1 root root 38 10月 15 15:42 /etc/alternatives/zabbix-web-font -> /usr/share/fonts/dejavu/DejaVuSans.ttf
```
↑/etc/alternatives/zabbix-web-fontのリンク先を日本語対応したフォントに切り替える


#### 1.yumコマンドで日本語対応したフォントをインストールする

```java:
[root@zabbix-master ~]# yum install ipa-gothic-fonts ipa-pgothic-fonts
[root@zabbix-master ~]# ls -l /usr/share/fonts/ipa*
/usr/share/fonts/ipa-gothic:
合計 6092
-rw-r--r-- 1 root root 6235344  4月 12  2011 ipag.ttf

/usr/share/fonts/ipa-pgothic:
合計 6092
-rw-r--r-- 1 root root 6235712  4月 12  2011 ipagp.ttf
```

インストール後は/usr/share/fonts/配下に「ipa-gothic」と「ipa-pgothic」が追加される

#### 2.rmコマンドで/etc/alternatives/zabbix-web-fontのリンクを削除する

```java:
[root@zabbix-master ~]# rm /etc/alternatives/zabbix-web-font
rm: シンボリックリンク `/etc/alternatives/zabbix-web-font' を削除しますか? y
```

#### 3.yumインストールで追加した「ipag.ttf」か「ipagp.ttf」に再びリンクを作成する
今回はipa-pgothic(Pゴシック)でリンクを作成

```java:
[root@zabbix-master ~]# ln -s /usr/share/fonts/ipa-pgothic/ipagp.ttf /etc/alternatives/zabbix-web-font
[root@zabbix-master ~]# ls -l /etc/alternatives/zabbix-web-font
lrwxrwxrwx 1 root root 38 10月 19 15:43 /etc/alternatives/zabbix-web-font -> /usr/share/fonts/ipa-pgothic/ipagp.ttf
```

リンクを再作成後、ダッシュボードをリロードすると文字化けが解消されました。
![WS_2020_1019_001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518227/323ee079-6e17-b908-13dd-d4665bd2845f.jpeg)


# 備考
今回気になった点について調べてみましたが、十分な理解ができなかったので内容を鵜吞みにしないようお願いいたします。
- /etc/alternativesって結局何なの?
- ipa-XXX(ipaフォント)って何なの?



## /etc/alternativesって結局何なの?
Linuxが使用差や互換性問題を管理するためのディレクトリ
(Zabbixのフォント設定で生じる文字化けはこのディレクトリ(リンク設定)で生じていた)

## ipa-XXX(ipaフォント)って何なの?
IPA(情報処理推進機構)が公開しているシステムの種類を問わず無償で利用できる高品位なフォント
今回はyumインストールをしたがパッケージのダウンロードも可能

# 参考URL
## 原因調査：対応手順
- [Zabbix 4.0 LTS グラフ 日本語文字化けの修正方法 ※有識者からの意見を頂き更新](https://www.opensourcetech.tokyo/entry/2018/10/12/Zabbix_4.0_LTS_%E3%82%B0%E3%83%A9%E3%83%95_%E6%97%A5%E6%9C%AC%E8%AA%9E%E6%96%87%E5%AD%97%E5%8C%96%E3%81%91%E3%81%AE%E4%BF%AE%E6%AD%A3%E6%96%B9%E6%B3%95)
- [【Zabbix】グラフ表示したときに文字化けするときの対処法！](https://pig-log.com/zabbix-mojibake-font/)

## /etc/alternativesについて
- [通信用語の基礎知識](https://www.wdic.org/w/TECH//etc/alternatives)

## IPAフォントについて
- [IPA 独立行政法人 情報処理推進機構](https://www.ipa.go.jp/osc/ipafont)


# 追記
「zabbix-web-japanese」をインストールするのみで対応可能とコメントをいただいたので試してみた。
(zabbixをインストール後、マシンを文字化けするところまで戻して実施) 
  
```java:
[root@zabbix-master ~]# yum install zabbix-web-japanese
```
この後、ダッシュボードをリロードしたら解決しました。