OmniAICreator/Qiita-1.07M huggingface dataset:
Wordpressのインストール及び設定

#はじめに
[前記事](https://qiita.com/Lana141/items/984063cb4016cb596593)
こちらの前の記事で構築した環境を前提にWordPressのインストールと設定を行っていきます。

##Wordpressのダウンロードとインストール
１. 作成した環境のコンソール上で下記コマンドを順番に実行します。

```
1. Wordpressのダウンロード　
sudo wget https://wordpress.org/latest.tar.gz
2. ダウンロードしたファイルの展開　
sudo tar xzvf latest.tar.gz
3. Apacheの指定ディレクトリにファイルを移動
sudo mv wordpress/* /var/www/html/
4. httpdのリスタート
sudo service httpd restart
```

##DBの作成
Wordpressで使用するためのDBを用意します。

１. EC2から作成したDBへ接続しスキーマを作成。

```
1. Wordpress用のスキーマがないことを確認　
show databases;
2. スキーマを作成(今回の名前はwp_dbとします)
CREATE DATABASE wp_db;
3. 作成されていることを確認
show databases;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2514161/4f0eca34-15f2-cafd-853f-3745657bfabe.png)

##WoredPress側からのDBの設定

Wordpressで使用するDBスキーマの作成は完了したのでブラウザ上からWordPress側のDB設定を行います。

１. ブラウザで下記のアドレスを開き『Let’s go!』を押下。

```
http://EC2のパブリックIPアドレス/wp-admin/setup-config.php
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2514161/b95f47dd-4ef9-7034-ebee-acddfb34c345.png)

２. 下記のような画面が出てくるので必要な情報を入力し『submit』を押下。

```
Database Name: 先ほど作成したスキーマ名(今回の場合はwp_db)
Username: 作成した任意のDBユーザー
Password: パスワード
Database Host: 作成したRDSのエンドポイント
Table Prefix: 複数のWordPressインストールを実行する場合は、これを変更します

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2514161/be145242-a772-42bd-d01a-4f7f4aab25b3.png)

３. 正常にいくと下記のような画面が表示されるので画面に表示されたテキストをコピー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2514161/333cf26c-ae47-617d-d860-1439dce89f06.png)

４.  コンソールに戻り下記ディレクトリにphpファイルを作成。

```
ディレクトリ: /var/www/html
phpファイル名: wp-config.php
```

５. 作成したphpファイルに先ほどコピーしたテキストを張り付けて保存。

６. phpファイルの作成が完了したらブラウザ上に戻り『Run the installation』を押下。

##まとめ
下記の画面が出れば環境構築は完了です。
あとは、Wordpress用のユーザーやパスワードを登録するだけになります。
細かい設定やプラグインの導入等はあるかとは思いますがこの記事では省きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2514161/9277959b-70e3-df4f-ac9f-1d72c84fee33.png)
Laravelのトランザクションに後処理を突っ込みすぎないで。。。

#タイトル通り、トランザクションに後処理を突っ込みすぎないで。。。
try,catchでエラー捕捉すればいいだけなのだが、こんなコードに出会った

```php
        DB::beginTransaction();
        try {
          // 1.データ取得する
　　　　　　　　　　　　　　　　　　　　// 2.取得したデータで条件分岐処理
          // 3.保存処理
          // 4.成功時にメール送信処理
        } catch (Exception $e) {
            DB::rollBack();
　　　　　　　　　　　　　　　　　　　　　　　// 5.失敗時にメール送信処理
        }
        DB::commit();
```
トランザクションの中で1~5の処理をする必要はないが、全てぶち込まれていた（笑）
少なくとも、1,4,5は間違いなく、トランザクションの外で行った方がいいだろう
そもそも、複数テーブルに安全に保存するためにトランザクションを使用しているので、端的に言えば、トランザクションの中は複数テーブルに保存する処理だけ記載すればいい(場合によりけり)
1,2はトランザクションの前にやれば良いだけなので、今回は、4,5にフォーカスを当てていく

##でもトランザクションの成否ってどうやって求めんの？
4,5をトランザクション外へ出すには、トランザクションが成功したのか、失敗したのかを知らなければならない。
どうすりゃいいんだ。。。と思ったら、さすがLaravelさん
抜かりはなかった！

トランザクションメソッドを使用して、それを変数に入れてやる
トランザクションが成功した場合はreturnで値を返してあげれば、保存したインスタンスがそのまま帰る
下記の例で言うと、Userインスタンスが帰る

```php
       $result = DB::transaction(function() use($user) {
           $user->save();
           return $user;
       });
```
では、失敗した時は？
Throwableクラスが帰ってきた！
となると、例外はcatchで捕捉できるので、最終的には下記の形に落ち着いた。

```php
        try{
            $result = DB::transaction(function() use($user) {
                $user->save();
                return $user;
            });
        }catch(\Throwable $e){
            Log::error($e->getMessage());
            // 5.失敗時にメール送信処理
        }
　　　　　　　　　　　　　　　　　// catchで早期returnすれば、わざわざif文で$userの存在をチェックする必要はないような・・・
        if ($user) {
          // 4.成功時にメール送信処理
        }
```

少し冗長かもしれないが、保存処理はトランザクションに任せて、トランザクション成功と失敗の処理はトランザクションの外に分離できた。
トランザクション内に余計な処理が紛れないので、可読性もよくなったと思う。

##教訓
トランザクションを使うにも、本当にトランザクション内でやらなければいけないのか考えるべし！
多少、冗長でも可読性は大事！
トランザクションの成否が取得できるなら、データ保存後の処理はトランザクションの外に書こう!
ubuntuサーバのcpu, memory, storageをコマンドラインから取得する

それだけです。


cpu

```
$ grep cpu.cores /proc/cpuinfo | sort -u
cpu cores      : 2
```


memory

```
$ free -h
              total        used        free      shared  buff/cache   available
Mem:          1.9Gi       363Mi       103Mi       3.0Mi       1.5Gi       1.4Gi
Swap:         4.0Gi        23Mi       4.0Gi
```

storage

```
$ df -h 
/dev/sda1        39G   12G   27G  31% /
```
Clear Linux 試してみた　SMB編

#まず何やるか？
sshは出来たので、リモートの別荘からアクセスするようにはしたのだが、リモートから逆に自宅のサーバにアクセスするとGUIが欲しくなって、RDPを入れようとしてもちょっとドキュメントが見つからず、こちらはハードルが高そう。
と言うことで、今回はhostnameの変更とSambaをとりあえず入れてみた。

```
$ sudo swupd update
$ sudo swupd update
Password: 
Update started
Version on server (35790) is not newer than system version (35790)
Update complete - System already up-to-date at version 35790
```

システムが付けるHostnameはアホほど長いので当然誰でもすぐ変えたくなる。

```
clr-3b3396ac4b5a42f4ba461415b69db1d6~ $ sudo hostnamectl set-hostname hogehoge
Password: 

hogehoge $ sudo reboot
```
これで完了

## samba
$ sudo swupd bundle-add samba
$ sudo mkdir /etc/samba
$ sudo vi /etc/samba/smb.conf

なんと、Ubuntuの様にはDirやConfファイルを作ってくれたりはしない！自分で作るんですね。

```
[Global]
map to guest = Bad User

[SharedDrive]
path=/home/clear/myshareddrive
read only = no
guest ok = no
browsable = yes
valid users = user-1 user-2
```

$ sudo mkdir /home/clear/myshareddrive
$ sudo chmod 755 /home/clear/myshareddrive
$ sudo chown user-1.user-1 /home/clear/myshareddrive
この辺りは自分で適当に考えてね。

さて、いよいよスタート

```
$ sudo systemctl enable --now smb
● smb.service - Samba SMB Daemon
     Loaded: loaded (/usr/lib/systemd/system/smb.service; enabled; vendor prese>
     Active: active (running) since Wed 2022-02-02 23:37:26 JST; 18s ago
       Docs: man:smbd(8)
             man:samba(7)
             man:smb.conf(5)

```

つながるかの確認は

```
$ smbclient //127.0.0.1/ShareDrive
Password for [WORKGROUP\hogehoge]:
tree connect failed: NT_STATUS_BAD_NETWORK_NAME
```

なにー！　となってトラブルシュートしました。結果は・・・

ShareNameとDriveNameが間違っていた。
日本人にとって、こんな名前を例に付けるヤツが憎いわ！
正解　SharedDrive　
間違い　ShareDrive
（path名も同じだから）

これに気づくのに小一時間・・・

```
$ smbclient //127.0.0.1/share
Password for [WORKGROUP\hogehoge]:
Try "help" to get a list of possible commands.
smb: \>
```

お疲れでした。

参照リンク
https://docs.01.org/clearlinux/latest/guides/maintenance/hostname.html
https://docs.01.org/clearlinux/latest/tutorials/smb-server.html#smb-server
Ender5 Pro with Bigtreetech SKR2 #2 (BLTouch)

[前回セットアップしたマザーボード](https://qiita.com/tanutanup/items/6b5e6f480f2a2d1a1f2c)に、ベッド高さ計測センサ"BLTouch"を追加することで、印刷物の剥がれや反り・歪みを防止しようと思います。

# 背景

3Dプリンタの印刷面(プラットフォームやベッドなどと呼ばれる)は、たいていネジによる高さ・傾きの調整機構がある。![ManLeveling.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/f62301a6-4400-e6bd-3064-8a3b7c48e38c.jpeg)

ノズルをHOME位置まで動作させた状態でノズルとベッドの距離を0.1～0.2mmに調整するのだが、ノズルがXY平面上どの位置に移動したとしても同じ高さになっていなければならない。実際の方法としてはノズルをベッドの四隅に移動させ、A4コピー用が引っかかる程度にネジを回すのだが、一箇所のネジを調整すると他の位置に影響するうえ、印刷毎に調整しないと少しずつズレていくので意外と面倒である。

3Dプリンタにおける印刷物とベッドの密着性はとてもシビアで、印刷し始めは問題ないように見えても、数時間後出来上がったものは無残にも剥がれて失敗となってしてしまう。

# 必要なもの
- BLTouchセンサ
    - 3DTouchセンサというコピー品もあるが、ほぼ品質は問題ない(個人的な感想)。
    - Creality社製センサもあるが、購入したもののピンアサインが分からず動作せず。
- BLtouchセンサ用ブラケット
    - ヘッドにセンサを取り付けるために必要

# BLtouchセンサの設定

BLTouchセンサ設定の有効化(Configration.h)

```cpp
#define BLTOUCH
#define NUM_SERVOS 1

```

レベリング設定(Configration.h)。

```cpp
// ノズル先端からBLTouchセンサ先端の位置を測って記入(X,Y,Z）。Zは後でしっかり調整するのである程度。
#define NOZZLE_TO_PROBE_OFFSET { -44.5, -15.0, -5.16 }
  //  中略
#define Z_CLEARANCE_BETWEEN_PROBES  4 // Z Clearance between probe points
#define Z_CLEARANCE_DEPLOY_PROBE   5 // Z Clearance for Deploy/Stow
  //  中略
#define Z_MIN_PROBE_REPEATABILITY_TEST
  //  中略
#define AUTO_BED_LEVELING_BILINEAR
 //  中略
#define RESTORE_LEVELING_AFTER_G28
 //  中略

// 5*5で25点の補正
#define GRID_MAX_POINTS_X 5
 //  中略
#define EXTRAPOLATE_BEYOND_GRID
 //  中略
#define ABL_BILINEAR_SUBDIVISION
 //  中略
#define LEVEL_BED_CORNERS


```

Z高さ調整はBLTouchに統一するため、ホーミング調整をBLTouchに変更(Configraltion.h)

```cpp
#define Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN
#define USE_PROBE_FOR_Z_HOMING
 // 中略
#define Z_SAFE_HOMING
 //  中略
#define HOMING_FEEDRATE_MM_M { (20*60), (20*60), (4*60) }

```

LCDディスプレイのBLTouchのZオフセット用メニューを有効化(Configration_adv.h)。


```cpp
#define PROBE_OFFSET_WIZARD
```

印刷しながらZオフセット調整を行うためにベイビーステップを有効(Configration_adv.h)。

```cpp
#define BABYSTEPPING
```

## 試運転

1. LCDにレベリングの警告が出るが無視。
2. Zホーミングを実施。
3. この時Z-OFFSETメニューでA4用紙一枚分の厚さになるように、Z-OFFSETを調整。
4. ステッピングモータをDisableして、四隅を調整(通常の動作と同じ)。
5. オートレベリングを実施しEEPROMへ書き込み(これ以降1のエラーは出ないはず)。


# Next...

次回はフィラメントランアウトセンサの設定を実施します。
constとは？定数について

初心者の勉強記録兼忘備録です。

#constとは何か
変数宣言をする際、アクセス修飾子と型の間に"const"をつけることで値が定数（固定値）となり、宣言後はその値を変更することができない。

#なぜ必要なのか
プログラムを書く上で変化しない値をいろいろな場所で何度も使いたいことがある。constを使用することにより、他クラスでもこの定数が使用できる。
他クラスで使用する場合はstaticと同様にクラス名にドットを付けることで使用可能。


###使用例
```c#:ExampleA.cs
public class ExampleA : MonoBehaviour
{
  //定数
  private const int ValueA = 100
  private const string ValueB = "abcde"

  //変数
  private int ValueC = 100;
  private string ValueD = "abcdef";
}
```

```c#:ExampleB.cs
public class ExampleB : MonoBehaviour
{
  public void Start()
 {
  //ExampleAクラスからValueAを使いたい場合
  Debug.Log(ExampleA.ValueA); //ValueAの値100がコンソールに出力される
 }
}
```

参考記事
[定数 - 未確認飛行C](https://ufcpp.net/study/csharp/sp_const.html)
[C#初心者のための基礎！#3値の扱い方。変数と定数をわかりやすく解説！](https://anderson02.com/cs/cskiso/cskisoniwari-03/)

間違えている場合は遠慮なくご指摘ください。
Ruby導入方法

正直良くわかってない部分が多いがメモがあったので起票する

### CentOSの準備         
  + VMwareにてCentOSをインストール 
      気が向いたら別途作成・・・

      ```
      VMware Workstation 16
      CentOS 7.8
      cpu1 mem2G
      ```

---

### rbenvインストール
  + gitよりrbenvを入手する

    ```
    # cd 
    # yum install git
    # git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
    ```
  + バッシュのプロファイルにパスを通す
 
    ```
    # echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
    # echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
    # cat ~/.bash_profile
    ```

  + 一度ターミナルを閉じ再ログインしてrbenvがインストールされたことを確認する
 
    ```
    # rbenv
    # rbenv -v
    ```
    
---

### rubyインストール
  + ルビービルドを入手する
  
    ```
    # mkdir -p "$(rbenv root)"/plugins
    # git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
    ```
  + rbenvにてインストール可能一覧を表示する
    大文字のLは過去バージョンもすべて表示される
  
    ```
    # rbenv install -l
    # rbenv install -L
    ```
  + 必要なツールを事前にインストールする
    rubyの2.6.6をインストールする際に圧縮がbz2で警告が出たため事前にbzip2をインストールする
    アーカイブはbz2圧縮なのかもしれない

    ```
    # yum install bzip2 gcc openssl-devel readline-devel zlib-devel
    # rbenv install 2.6.6
    ```
  + ルビーインストール
    10分程度?かかったりする

    ```
    # rbenv install 2.6.6
    ```

---

### ビルドしたバージョンをデフォルトで使用する
  + ビルドしたバージョンをデフォルトで使用する
    ※意図しないバージョンが出た際はターミナルを起動し直す

    ```
    # rbenv global 2.6.6
    # ruby -v
    ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-linux]
    ```

---

### Railsの導入
  + 
    編集中
Grepコマンド

# Grepコマンド

ファイル名を表示したいときに便利なコマンド
使い方

```
$ grep <検索ワード> <ファイル or フォルダ>
```


## 使用例
test1.mdとtest2.mdを作成し、grepした結果

```
$ ls
test1.md  test2.md
```

```
$ cat test1.md
このファイルはテスト1です
```

```
$ cat test2.md
この
ファイルは
テスト2
です
```

```
$ grep "" *
test1.md:このファイルはテスト1です
test2.md:この
test2.md:ファイルは
test2.md:テスト2
test2.md:です
```
## 注意点
ファイルが1つの場合はファイル名は表示されない

```
$ ls
test2.md
```

```
$ cat test2.md
この
ファイルは
テスト2
です
```

```
$ grep "" *
この
ファイルは
テスト2
です
````
Ubuntu Server 20.04.3 LTS 構築#6 セキュリティ設定4-2

実施日:2022/01/18～
<<今回の内容>>
ウイルス定義更新の自動更新の続き

crontab -eの設定ばかりに固執すぎてしまい、cron.dに設定ファイルを格納してから
テキストエディタを使用して定期コマンドを作成。

設定した時間になって、catコマンドでログを確認すると、いつもの通りに定期コマンドが
実行されたログはなし。

色んなサイトを見て調べてみると、シェルの箇所がデフォルト設定値が/bin/shになっているが、
/bin/bashに変更をしている説明文を発見。
試しに私の設定ファイルを/bin/shから/bin/bashに変更し。
定期コマンドに設定した時間を経過したので、catコマンドで再度、ログを確認。
すると、今まで何も変わらなかったターミナル画面に変化がありました。

表示されていたメッセージは下記の通り
ERROR:/var/log/clamav/freshclam.log is locked by another process

他のプロセスがロックしているので、上記のエラーメッセージが表示されてしまう。

次回はこのエラーを解消して、自動設定を終わりにしたいと思います。
IstioのService Entry

## Service Entry とは（[Istioのサイトより](https://istio.io/latest/docs/reference/config/networking/service-entry/)

> * ServiceEntryは、Istioの内部サービスレジストリに追加のエントリを追加し、メッシュ内の自動検出サービスがこれらの手動で指定したサービスにアクセス/ルーティングできるようにします。
* ServiceEntryは、サービスのプロパティ（DNS名、VIP、ポート、プロトコル、エンドポイント）を記述します。
* これらのサービスは、メッシュの外部サービス（例：Web API）、またはプラットフォームのサービスレジストリの一部ではないメッシュ内部サービス（例：Kubernetesのサービスと対話するVMのセット）である可能性があります。
* さらに、ServiceEntryのエンドポイントは、workloadSelectorフィールドを使用して動的に選択することもできます。
* これらのエンドポイントは、WorkloadEntryオブジェクトを使用して宣言されたVMワークロードまたはKubernetesポッドにすることができます。
* 1つのサービスでポッドとVMの両方を選択できるため、サービスに関連する既存のDNS名を変更することなく、VMからKubernetesへのサービスの移行が可能になります。

## やりたいこと

2つある。

1. クラスタ外のサービスをサービスメッシュの外部サービスとして識別させて、Kialiで表示させたい
2. クラスタ外の名前解決ができない自前のサーバをサービスメッシュの外部サービスとして識別させて、アクセスしたい
3. サーバの自己証明書の検証をスキップさせたい or 真面目に検証したい

## クラスタ外のサービスをサービスメッシュの外部サービスとして識別させる

YAMLをつくる。

* 外部サービスの宛先は、dropbox、google、facebookとする
* サービスメッシュの外部サービスとして識別させる
* リスナーは443;TLSでスキーマはhttps
* 名前解決はDNSでやる

```yaml:extapi-se.yaml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-svc-https
spec:
  hosts:
  - api.dropboxapi.com
  - www.googleapis.com
  - api.facebook.com
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS
```

リソースをつくる

```
oc apply -f ./extapi-se.yaml
```

bookinfoサンプルアプリのratingsのPodに侵入して、リクエストを撃ちまくる

```bash
while true; do curl -k https://api.facebook.com; sleep 1; done
```

Kialiを見る。ちゃんとratingsのPodからexternal-svc-httpsへの経路が表示されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/f421d56d-3b48-271e-756c-f5fea2726aa7.png)

## クラスタ外の名前解決ができない自前のサーバをサービスメッシュの外部サービスとして識別させて、アクセスしたい

Serviceをつくって、applyする。

```yaml
apiVersion: v1
kind: Service
metadata:
  name: external-myapi
spec:
  clusterIP: None
  ports:
  - protocol: TCP
    port: 443
```

Endpointsをつくって、applyする。
`192.168.50.231`は自前のサーバのIPアドレス。

```yaml
apiVersion: v1
kind: Endpoints
metadata:
  name: external-myapi
subsets:
  - addresses:
    - ip: 192.168.50.231
    ports:
    - port: 443
```

ServiceEntryをつくって、applyする。

* hostsにはServiceのhostnameをいれる（Endpointsに通じる）
* Istio側での名前解決はNone

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-se-myapi
spec:
  hosts:
  - external-myapi.default.svc.cluster.local
  ports:
  - number: 443
    name: https
    protocol: TLS
  location: MESH_EXTERNAL
  resolution: NONE
```

bookinfoサンプルアプリのratingsのPodに侵入して、リクエストを撃つ。
うまくいった。

```bash
$ curl -k https://external-myapi.default.svc.cluster.local
Example web content
```

`-k`（証明書検証を無視）を外すとエラーになる。

```bash
$ curl https://external-myapi.default.svc.cluster.local
curl: (77) error setting certificate verify locations:
  CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
```

## サーバの自己証明書の検証をスキップさせたい or 真面目に検証したい

TODO
Doctrine forAllでmust be of type ○○, int given,が出る

# サンプルコード(エラーがでる)
```php
$collection=new ArrayCollection(["a","b","c"]);
if($collection->forAll(function(Hoge $hoge){
   //何か処理
}
```

# エラー内容
>Argument #1 ($hoge) must be of type Hoge, int given

# 背景
filterやmapなどと違い、forAllは与えられた無名関数に(key,value)の組を与えます。
ドキュメント：https://www.doctrine-project.org/projects/doctrine-collections/en/1.6/index.html#forall

#修正
```php
$collection=new ArrayCollection(["a","b","c"]);
if($collection->forAll(function(int $key,Hoge $hoge){
   //何か処理
}
```

#あとがき
filterとかから書き換えたときに陥りがちなエラーで、ドキュメントを見れば一発ですが意外と気づかないもんですね。
AWSネットワークに関するまとめノート

まとめノート。詳しくはAWS のネットワークで知っておくべき10のことの動画を参照してください。

<!-- 関連
https://pages.awscloud.com/JAPAN-event-OE-At-least-10-Network-2020-reg-event-CP.html
https://aws.amazon.com/jp/about-aws/global-infrastructure/regions_az/
https://aws.amazon.com/jp/compliance/data-center/data-centers/
https://s3-accelerate-speedtest.s3-accelerate.amazonaws.com/en/accelerate-speed-comparsion.html

privatelink hands-on
https://aws-saas-privatelink.workshop.aws/ -->


#### ec2インスタンスだけからみえる専用ネットワークを使用してメタデータを取得

手順①
- sshで起動したインスタンスに接続
- インスタンスの中で
`'http://169.254.169.254/latest/meta-data/'`下にある様々なメタデータを取得する
手順②
- sshで起動したインスタンスに接続
- インスタンスの中でamzn-linuxなら`ec2-metadata`コマンドで取得。


```

実行中インスタンスのみから取得できクレデンシャル不要

- 公開鍵を取得
[ec2-user@ip-172-......-13 ~]$ curl 'http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key'
> ssh-rsa AA......mM4KJ hoge

- パブリックipv4アドレスを取得
[ec2-user@ip-172-......-13 ~]$ curl 'http://169.254.169.254/latest/meta-data/public-ipv4'
54.199.119.48
```

- 例えばec2インスタンスに公開鍵がなぜ存在するかというと、ec2インスタンスブート(起動)時に
`http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key`
から公開鍵を取得し`/home/ec2-user/.ssh/authorized_key`に配置しているかららしい。



#### 通信経路
インターネット-トランジットセンター-AZ-blackfoot-VPC内のEC2インスタンス


#### awsネットワークを使用した通信の話
AZ
意味のある距離
- レイテンシ
- 地質的条件
などを考慮し複数のデータセンターからなる


- インターネットはISPの集合体なので全体として可用性の保証がない
- オリジン エンドユーザに対してサービスを提供するもの

- AWS GLOBAL ACCELERATORでは低いレイテンシと高いアベイラビリティが実現できる
    - エンドユーザ-AWS間の距離をなるべく短くし、AWS-WEBサーバ間の距離を長くとることで安定したAWSネットワーク内で通信できる

- aws edge services
    - route53 dnsはインターネットコミュニケーションにおける起点
    - cloud front ユーザを一番近いエッジロケーションに誘導して配信を高速化/キャッシュを活用しオリジンの負荷をオフロード/aws global networkによる非キャッシュコンテンツ高速化


#### VPC接続

- VPCだけで通信したいというニーズが強く多くのユースケースを提供。

- vpc peering 1vs1 例：東京-オレゴン
- trainsit vpc スポークを起点に接続を構成
スケールする構成
- aws privatelink 1 vs Nでスケールさせたい時 アプリの共用に。
- aws transit gateway 1 vs 1,1 vs N ネットワークの共用に。

#### VPC-オンプレの接続手段
- client vpn 
- site-to-site
    - ipsec vpnを使用 例：拠点-awsの通信
    - virtual private gatewayもしくはtransit gatewayと接続
    - 少数トラフィック/低価格/
    - 構成
        - VGW-冗長化された2つトンネル-CGW
- direct-connect 専用線を使用して拠点-awsへ接続
    - パフォ/大量のトラフィック/安定性

#### Q.awsはインターネット攻撃にいかに対処しているのか

- A. pop(point of presence)=エッジロケーションにaws shield ddos scrubbingを併存させてセキュリティを高めている。

- aws waf
    - 防御全般
- aws shield
    - managed ddos protection
    - ddos緩和サービス
- aws firewall manager
    - ファイアウォールの複数アカウント単位での一元管理を提供

所感
webサービスからエンドユーザまでの流れやvpcができた理由など、黒本にない経緯や視点の話が面白く記憶に残った。
TrailheadのApexインテグレーションサービスで苦労した点


##前提
・今回の備忘録は下記のModule
https://trailhead.salesforce.com/ja/content/learn/modules/apex_integration_services/apex_integration_webservices
・筆者のレベルは最近Rangerになったばかりの初心者
・RESTのこともよくわかってない
・回答は載せない（あくまでもつまづきポイントのみ）
##苦労ポイントその１
参照関係があることにより特殊なURLMappingが必要だった。

Module内ではCaseを指定するだけで良かったためURLのマッピングがシンプルで良かった。
しかし、ハンズオンでは参照関係のあるAccountとContactを意識しなければならないのでどのようなURLになるかを知っている必要がある。

誤答

```apex:wrongcode.apxc
@RestResource(urlMapping='Accounts')
```

正答

```apex:rightcode.apxc
@RestResource(urlMapping='/Accounts/*/contacts')
```

##苦労ポイントその２
AccountIdを取り出すのに間に挟まれたIdを取る方法がわからなかった。

その１からURLは下記のような構造になり、Trailを進めているだけではわからなかった。

```apex:url
'https://yourdomain.my.salesforce.com/services/apexrest/Accounts/' + AccountId + '/contacts';
```


取り出し方は

```apex:getAccountId.apxc
String accountId = request.requestURI.substringBetween('/Accounts/', '/contacts');
```

##以上
Trailheadはこういうところで躓く人が自分以外にもいるんじゃないかと思って記事を作成してみました。
これで少しでもハンズオンチャレンジで余計な時間をかける人が減ればなと思います。
【備忘録】document.querySelector()をconsole.logしたときオブジェクトで見たかった

 【備忘録】document.querySelector()をconsole.logしたときオブジェクトで見たかった

---

どうやら`console.dir()`でいいみたい
console君しっかり便利

---



```html
...
<input type="text" class="target" />
...
```

たとえばこんな要素を取得したいとき

```javascript
const inputElement = document.querySelector('.target');
```

と書いてうんぬんかんぬんすると思うのですが
こいつを`console.log(inputElement)`すると

```javascript
<input type="text" class="target" />
```

こう返ってくるわけですね
まぁそれはいいんですがたまにざっとこの要素が持つ情報を見たいときWindowオブジェクトのように

```javascript
Window {window: Window, self: Window, document: document, name: '', location: Location, …}
```

みたいな感じで`key: value`にしたかったので

```javascript
console.log(Array(inputElement))
```

こうすると配列の中にオブジェクトとして要素が格納されてチェックできます


ちなみにほかにやり方があるのであれば教えていただけると幸いです。
docker Elasticserchで[429 Too Many Requests]が出た時の対応


# 事例

* 環境
 * image:: elasticsearch:7.12.1
 * os:: mac

エラー例

```
 [429 Too Many Requests] {"error":{"root_cause":[{"type":"cluster_block_exception","reason":"index [index-name] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block];"}],"type":"cluster_block_exception","reason":"index [index-name] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block];"},"status":429}
```

# 原因

```
"blocks": {
        "read_only_allow_delete": "false",
}
```

こちらの設定が入っているとディスク容量がデフォルト95% を超えるとインデックスが読み取り専用となるため書き込みができなくなっていた

https://www.elastic.co/guide/en/elasticsearch/reference/6.7/disk-allocator.html


# 対処

## docker が使っているサイズチェック

```
> docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          35        5         11.54GB   9.134GB (79%)
Containers      5         0         6.635MB   6.635MB (100%)
Local Volumes   140       3         32.3GB    26.93GB (83%)
Build Cache     89        0         1.048GB   1.048GB
```

## 削除コマンド

使用していないvolumeの削除

```
> docker volume ls -qf dangling=true | xargs -r docker volume rm
```

## 結果

```
> docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          35        5         11.54GB   9.134GB (79%)
Containers      5         0         6.635MB   6.635MB (100%)
Local Volumes   3         3         5.374GB   0B (0%)
Build Cache     89        0         1.048GB   1.048GB
```

Local Volumeを削除したらデータを投入することができました。
Lambdaの明瞭な出力ログ、logのデバック方法  [Python, Node.js]

# はじめに
Lambdaの出力ログは、CloudWatchLogsで確認しますが、json形式の明瞭なログ出力を書き留めます。

#Python
DynamoDBの数値を取り出す際、データとしてDecimal(数値)として取り出されますが、json.dumpsを実行すると、エラーが起きました。
そのため、Decimalを取り除くロジックをつけています。

`ensure_ascii=False`は、文字化け対策です。

```python
import json
from decimal import Decimal

# json形式でログを出力するため、Decimalがある場合取り除く
def decimal_to_int(obj):
    if isinstance(obj, Decimal):
        return int(obj)


def lambda_handler(event, context):

print("Received event:" + json.dumps(event, default=decimal_to_int, ensure_ascii=False))
```

![スクリーンショット 2022-02-02 22.42.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/deb34750-cd6f-4962-eaaf-e09542954b4d.png)

# Node.js
Node.jsの方は、1行でかけました。

```js
exports.handler = (event, context, callback) => {

console.log("Received event:", JSON.stringify(event, null, 2));
```
【python】Wordcloudを用いた形態素解析

![wordcloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2471428/beaada41-7017-c27f-563f-e14c9f7d2dad.png)
#はじめに
ニュースでこんなグラフをみたことはありませんか？
文章を形態素解析し、wordcloudで文字の出現頻度を可視化したものです。
形態素解析は文章を<font color="DeepPink">単語単位で区切りそれぞれの単語に情報を付与する手法</font>です。
本ページでは最もシンプルにwordcloudで文字の出現頻度を可視化する方法を示します。

#環境設定
###①Mecabのインストール
形態素解析にはMecabを用いました。インストールの仕方が少し複雑でしたが、下記のページが一番シンプル化と思います。

https://self-development.info/mecab%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6python%E3%81%A7%E4%BD%BF%E3%81%86%E3%80%90windows%E3%80%91/

###②wordcloudのインストール
pip install wordcloud などでwordcloudもインストールします。

###③日本語フォントのインストール
wordcloudはデフォルトでは日本語に対応していないので、適当な日本語フォントを読み込ませる必要があります。下記から"ipaexg.ttf"をダウンロードし、pythonファイルと同じ階層に格納しました。

https://moji.or.jp/ipafont/ipaex00401/


#プログラム
Mecabで形態素解析した後、nodeに格納された結果をwhile文で順に取得しています。
助詞や助動詞なども抽出されてしまうので、「名詞」「動詞」「形容詞」に限定して単語を抽出しています。
下記プログラムを実行すると同じ階層に「wordcloud.png」が保存されます。
Mecabの扱い方は下記ページを参考にしました。

https://zerofromlight.com/blogs/detail/56/

```python:runWordCloud.py
import MeCab
from wordcloud import WordCloud

# 解析したい文章
text = "みかんは好きだけどオレンジを食べたいときもある。だけどみかんは栄養もあるし、みかんは小さいころから食べていたから、オレンジよりもみかんが好きだ。"

#単語の分割
m = MeCab.Tagger ("-Ochasen")

# 形態素解析
node = m.parseToNode(text)
words=[]
word=""
while node:
    # node.feature：CSVで表記された素性情報を取得
    # print(node.feature)
    hinshi = node.feature.split(",")[0]
    print(hinshi)
    if hinshi in ["名詞","動詞","形容詞"]:
        origin = node.feature.split(",")[6]
        word = word + " " + origin   
    node = node.next  # 書き忘れると無限ループになるので注意

# wordcloudで可視化
fpath = "./ipaexg.ttf"
wordcloud = WordCloud(background_color="white",font_path=fpath, width=600,height=400,min_font_size=15)
wordcloud.generate(word)
 
wordcloud.to_file("./wordcloud.png")
電話帳作成問題を解いてみた

# はじめに

[Ruby初心者向けのプログラミング問題を集めてみた](https://blog.jnito.com/entry/2019/05/03/121235)から、今回は電話帳作成問題を解いてみました。
自分が書いたソースコードと、先輩にいただいた回答例を紹介していきます。

以下の`IN`のような名前の配列を渡すと、`OUT`のように50音の音別にグループ分けされた配列が返るようにします。

- IN: `['キシモト', 'イトウ', 'ババ', 'カネダ', 'ワダ', 'ハマダ']`
- OUT: `[ ['ア', ['イトウ']], ['カ', ['カネダ', 'キシモト']], ['ハ', ['ハマダ', 'ババ']], ['ワ', ['ワダ']] ]`

## 要求仕様

- カタカナ文字列の配列を渡すと、ア段の音別にグループ分けした配列を返すプログラムを作成すること
- 各要素は 50 音順にソートもすること


# 自分が書いたソースコード

```ruby
class NameIndex
  KANA_GROUPS = [
    ('ア'..'オ').to_a,
    ('カ'..'ゴ').to_a,
    ('サ'..'ゾ').to_a,
    ('タ'..'ド').to_a,
    ('ナ'..'ノ').to_a,
    ('ハ'..'ボ').to_a,
    ('マ'..'モ').to_a,
    ('ヤ'..'ヨ').to_a,
    ('ラ'..'ロ').to_a,
    ('ワ'..'ン').to_a
  ].freeze

  def self.create_index(names)
    KANA_GROUPS.map do |kana_group|
      target_names = names.sort.select do |name|
        kana_group.include?(name[0])
      end
      [kana_group.first, target_names] unless target_names.empty?
    end.compact
  end
end
```

## 処理について

まず、定数`KANA_GROUPS`で、50音を行ごとに分けた配列を定義しています。

`create_index`メソッドでは、`KANA_GROUPS`をレシーバに`map`を使用し、
ループの中では、引数の`names`を`sort`で並び替えた後、`select`で特定の名前を取得しています。
`kana_group`の先頭の文字と、取得した名前たち(`target_names`)をセットにした配列を作成しています。

また、結果に`nil`が含まれてしまうので、最後に`compact`しています。

## 改善点

- `KANA_GROUPS`に、`ヴ`と`ポ`が含まれていない。
- `map`の中で、`names`に対して`sort`しているので無駄に処理が走ってしまう。
  - ループより前で、`sort`したものを変数に入れておくと良かった。
- 最後に`compact`しているので、無駄に処理が走ってしまう。
  - `map`+`compact`で書けるときは、`inject`を使うようにする。
  - `inject`が使えるときは、`each_with_object`を使うようにする。
- `name[0]`と`kana_group.first`、記法が統一されていない。
- `select`の部分は、別メソッドに切り出したほうが可読性が上がる。
  - どのような処理をしているのかがメソッド名から想像できるため、分かりやすくなる。

# 回答例

```ruby
class NameIndex
  SYLLABLES = [
    [*('ア'..'オ'), 'ヴ'],
    ('カ'..'ゴ').to_a,
    ('サ'..'ゾ').to_a,
    ('タ'..'ド').to_a,
    ('ナ'..'ノ').to_a,
    ('ハ'..'ポ').to_a,
    ('マ'..'モ').to_a,
    ('ヤ'..'ヨ').to_a,
    ('ラ'..'ロ').to_a,
    ('ワ'..'ン').to_a
  ].freeze

  class << self
    def create_index(names)
      names.sort.group_by(&method(:initial_syllable)).to_a
    end

    private

    def initial_syllable(name)
      SYLLABLES.find { |column| column.include?(name.chr) }.first
    end
  end
end
```

## 処理について

まず、定数`SYLLABLES`で、50音を行ごとに分けた配列が定義されています。
ア行は、配列展開が使用されており、`ヴ`も含まれています。

`create_index`では、引数の`names`を`sort`した後、`group_by`でグループ分けしたハッシュを配列にしています。
(`group_by`は、ブロックの返り値をキー、キーに対応する要素の配列を値とするハッシュを返します。)

`&method(:initial_syllable)`で、要素１つずつに対して、`initial_syllable`を呼んでいます。

`initial_syllable`メソッドでは、引数の`name`が属するグループの段を返すために、`SYLLABLES`から`name`の1文字目に当てはまる行の先頭を取得しています。

## 学んだこと

- 範囲オブジェクトを使うときは、必要な値が全て含まれているか確認する。
- グルーピングしたいときは、`group_by`が使えないか検討する。
- ループを回すときは、条件式が少なく書ける方をレシーバにする。
- 1つのメソッドで複数の処理をしすぎないようにする。(別メソッドに切り分ける。)

# まとめ

今回の電話帳問題を解いてみて、コードの統一感や、1行ずつのコードの役割を意識できていないように感じました。
今後はリファクタリングする時間を多く取って、より良い書き方ができないか、同じような処理はきちんと統一されているか、というところを意識して実装しようと思います。
(備忘録)Javascriptでのonclickの発火タイミング

Javascriptを書いていて、あれっ？ と思ったことがあったのでメモ。

```html
<details>
  <summary onclick="if(this.parentNode.open){this.innerHTML='折りたたむ'}else{this.innerHTML='展開する'}">展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>
```

`<summary>`タグがクリックされると`click`イベントを`onclick`で拾って、`parentNode`である`<details>`タグが`open`であるかを調べ、そうであるなら`<summary>`の中身を「折りたたむ」に、そうでなければ「展開する」にするコードだが、実際にやってみると…
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1874050/00810400-4500-4ccd-760e-cf71a78ca4b9.gif">
なんと、想定していたのと真逆の挙動をする。
これはclickイベントが、実際に親要素である`<details>`の`open`が`false`から`true`に変わる(またはその逆)前に発火してしまうからで、実際にはまだ`open`属性の値が変わっていないのにそれを参照してしまっている(alert()をonclick時に入れてみるとその挙動がわかる)。
暫定的な解決策として、「折りたたむ」と「展開する」を入れ替える。すなわち、

```html
<details>
  <summary onclick="if(this.parentNode.open){this.innerHTML='展開する'}else{this.innerHTML='折りたたむ'}">展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>
```

こうする。


※2022/2/4追記
コメントからよりいい方法をいただきました。`details`で発生する`ontoggle`イベントを拾うのがよいようです。上のコードを修正するなら、

```html
<details ontoggle="if(this.open){this.querySelector('summary').innerHTML='折りたたむ'}else{this.querySelector('summary').innerHTML='展開する'}">
  <summary>展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>
```

とすべきでしょう。実際には、三項演算子を使ってもう少し簡潔に、

```html
<details ontoggle="this.querySelector('summary').innerHTML = this.open ? '折りたたむ' : '展開する'">
  <summary>展開する</summary>
  <!-- ここにいろいろな内容... -->
</details>
```

とできます。
【Laravel 8.x/Schema Dump】１つのダンプファイルを異なるプロジェクトで使い回す方法

## Schema Dump機能

Laravel8から「Schema Dump」機能が追加されました。
マイグレーションファイルを１つのダンプファイルに圧縮して、マイグレーション作業を高速にしようという機能です。

以下コマンドでダンプファイルの作成が可能です。

```bash
php artisan schema:dump
```

詳しくは[こちら](https://blog.capilano-fw.com/?p=6877)

今回は、あるリポジトリで作成したダンプファイルを
他のリポジトリで使い回す方法を書き残します。
~~（これに丸一日費やしたなんて言えない。。）~~

## 設定方法

設定はとても簡単です。
以下のうち、どちらかを設定してください。

### パターン1 App/Providers/AppServiceProvider.phpに設定追加

bootメソッド内に下記の一文を追加してください。

```php

public function boot(){
 $this->app->useDatabasePath('../your-migration-repo/database')
}

```

### パターン2 bootstrap/app.php

**bootstrap/app.php**に以下を追加してください。

```php
//スキーマファイルのパスを設定
$app->useDatabasePath('../your-migration-repo/database');
```

## 結果

モデルのUTなどを含むマイグレーション作業が爆速になる！

モデルのUTについては、前はテスト実行から終了まで3分ほどかかっていました。
しかし、ダンプファイルを使用するように変更したところ、実行から終了まで1分未満に短縮されました。

ぜひSchema Dump機能を使ってみてください！
家の乾燥度を水分量で見えるようにした

室内の湿度とかが気になるお年頃で、温湿度マップを作ったりしています。

https://qiita.com/tosshie/items/6adf6d533527674aef2a

朝起きたときに家の中が乾燥していて、朝風呂に入ったり麦茶を作ったりすると家の中の水分量が増える感じを見えるようにしたくて、家の中の水分量を見える化しました。

![家の水分量グラフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849198/4727ad09-fe2a-44a3-82b3-e1d96b751247.png)

7時過ぎに2階の水分量が増えているのがわかります。麦茶を作っています(笑)
1F_2は洗濯物を干したり、朝風呂に入っている結果、少しずつ増えていっています。

単位はgなので、家の中に2リットルほどの水が水分量として含まれているようです。
朝の2時間でペットボトル1本分(500ml)ほどの水分が増えているのは驚きでした。
お湯をわかしたり、お風呂からの蒸気だったり、洗濯物からの水分だったりでかなりの水分量が増えていることを知りました。

#### 作り方

* データは取得されているものとします
    * switchbot温湿度計とラズベリーパイを使って部屋のデータを取得する方法は以下に記載しています
    * 他のやり方ででもデータがそろっていれば計算できます

https://qiita.com/tosshie/items/0b6a93a8e351cd801321

* 絶対湿度(g/m3)を求めます↓
    * `{絶対湿度}=217*(6.1078*10^(7.5*{気温の値}/({気温の値}+237.3)))/({気温の値}+273.15)*{相対湿度の値}/100`

* 部屋の容積を求めます
    * {容積(m3)} = 床面積(m2) * 高さ(m)
* 絶対湿度に部屋の容積をかけます
    * {水分量(g)}={絶対湿度(g/m3)} * {容積(m3)} 
* これをgoogle spreadsheet内で計算して、積み上げ面グラフにすれば完成です
生存時間分析のCox比例ハザードモデルをConcordance indexを使って評価する

# はじめに

生存時間分析の一つとして Cox 比例ハザードモデルがあります。
Python の生存時間分析ライブラリである `lifelines` を使ってモデルを作成すると、評価方法についていくつか選択肢があります。
ここでは Concordance index (c-index, C 統計量) を使った評価についてまとめます。

# lifelines で Cox 比例ハザードモデルを作成した際の summary

今回は Python の生存時間分析ライブラリ `lifelines` に入っている "ROSSI" データを使用します。
以下のコードを実行すると、Cox 比例ハザードモデルを作成でき、図のような summary が取得できます。

```python
import pandas as pd
from lifelines.datasets import load_rossi
from lifelines import CoxPHFitter
import matplotlib.pyplot as plt

rossi = load_rossi()

cph = CoxPHFitter()
cph.fit(rossi, duration_col='week', event_col='arrest')

cph.print_summary()
```

![スクリーンショット 2022-02-02 220426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542065/52f5c2e8-9596-2da2-319a-7c668cfae1bd.png)

モデルの評価で用いることができるのが、図の下の方にある `Concordance`、`Partial AIC`、`log-likelihood ratio test` の3つになります。
今回取り上げる `Concordance` は、上記の場合 0.64 になっています。

# Concordance について

Concordance (index) は C-index や C 統計量とも呼ばれ、1996年に Harrell らによって提唱された指標になります。
これは**生存時間の予測と実測の大小関係がどの程度一致しているかを表した指標**になっており、0~1 の値を取り、1 に近いほど良い結果となります。
また、医療統計分野の論文では「値が 0.8 より大きければ良い」という目安があるそうです。
ただし、値はあくまで目安であり、必ず超えていなければいけないわけではなく、例えば [DeepSurv](https://bmcmedresmethodol.biomedcentral.com/articles/10.1186/s12874-018-0482-1) の論文では Cox 比例ハザードモデルと Randam Survival Forest、DeepSurv のそれぞれの比較に Concordance index を用いています。

これらを踏まえて、例えば「Cox 比例ハザードを使用したモデル A とモデル B では、A の方が Concordance index の値が大きく、また目安となる 0.8 に近い値を出している。このことからモデル A の方が優れている」などと示すことができます。

# まとめ

Python で Cox 比例ハザードモデルを作成して生存時間分析する際のモデルの評価方法についてまとめました。
場合によっては AIC を使う方が良いという記事も見かけたのですが、`lifelines` で出力される `Partial AIC` の見方が分からなかったのでここについて知っている方がいたら教えていただければ嬉しいです。

# 参考

- [傾向スコアを用いた共変量調整による因果効果の推定と臨床医学・疫学・薬学・公衆衛生分野での応用について](https://ci.nii.ac.jp/naid/40015391518)
- [DeepSurv: personalized treatment recommender system using a Cox proportional hazards deep neural network](https://bmcmedresmethodol.biomedcentral.com/articles/10.1186/s12874-018-0482-1)
- [【生存時間分析による離反時期分析 その3】
Python の生存時間分析ライブラリー Lifelinesで予測した
「離反時期（顧客であるまでの期間）」の精度検証](https://www.salesanalytics.co.jp/datascience/datascience076/)
- [サービスの解約率・機械の故障率などが予測できる”生存時間分析”とは？](https://data.nifcloud.com/blog/survival-time-analysis_python/)
- [AICとc-index (concordance index)とはどう使い分けるべきなのか](https://tjo.hatenablog.com/entry/2014/01/02/233541)
登録フォームについて

###はじめに

今回は、ポートフォリオ作成で学んだ知識のアウトプットをしたいと思い、記事を書いています。


###登録フォーム

フォームの作成方法はさまざまですが、今回はform_withヘルパーを用いています。

form_withヘルパーとは？
form_withヘルパーはviewで簡単にフォームを作成できる、ヘルパーです。
また、フォームの送信先についても簡単に設定できます。

ラベルに"チーム名"のように記述することで、表示を変更することができます。


###コード
```_form.html.erb
<%= form_with(model: @user, local: true) do |f| %>
 
  <%= f.label :name, "チーム名" %>
  <%= f.text_field :name, class: 'form-control'  %>
   
   <%= f.label :prefecture_id, "活動地域" %>
　  <%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"select-box", id:"item-shipping-fee-status"}) %>
  
  <%= f.label :email, "メールアドレス" %>
  <%= f.email_field :email, class: 'form-control' %>
  
  <%= f.label :password, "パスワード" %>
  <%= f.password_field :password, class: 'form-control' %>
  
  <%= f.label :password_confirmation, "パスワード確認" %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>
  
  <%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>

```

###表示画面
![スクリーンショット 2022-02-02 21.27.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2346211/27b0a834-378a-f544-8dcc-a00ebb94473e.png)

###最後に

今回はフォームについての記事になっております。
初学者の記事なので参考程度に見てください。
また、どこか気になる部分がありましたら、コメントしていただきたいと思います。
【概要編】Windows Server Update Services(WSUS)とは？【初心者向け】

【概要編】と【設定・構築編】の２部構成でWindows Server Update Services(以下WSUS)について、記事にします。本記事は【概要編】なのでそもそもWSUSって何ですか？というところにフォーカスした記事になっています。具体的な設定例や構築方法については次回【設定・構築編】で記事にします。

# WSUSとは？
そもそもWSUSとは一言でいえば、windows Sever OSの機能の１つで「Windows OSのPCのアップデート管理」をするためのサービスです。
大きくは以下２つの機能を持っています。

①「Windows PCのアップデート管理」＝「管理しているPCのOSが勝手に更新されないように管理する」

②「WSUSがMicrosoftサーバからアップデートデータを取得し、PCに配布する」=「Microsoftサーバへの通信を仲介して、管理しているPCに直接アップデートデータを取得させない」

【機能イメージ】
![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/3a474ed8-bfe0-3736-ee72-8cf1645aa376.png)


# Windows OSのアップデートとは？
Windows OSはセキュリティホールが見つかったり、システムにバグがあったりするとMicrosoftさんが修正するプログラムを送ってくれます。
配布してくるプログラムの内容（修正や、新機能追加など）によって、"Feature Update(FU)"とか"QualityUpdate (QU)"と言われます。

ざっくりイメージですが以下のような感じです。
◆FU＝OS更新を伴う大きな変更
◆QU＝既存のプログラムやセキュリティの更新などの軽微な変更

ちなにお使いのWindows PCのOS versionはデスクトップ右下（スタートボタン横）の検索欄に”Winver”と入力すれば表示されます。
![スライド1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/3a485408-513b-768d-3977-579caa286e77.png)



# Windows OSのPCのアップデート管理の必要性
何となく最新版にしておけばいいだろというのも間違いではないのですが会社によって色々な理由があり、Windows OSのPCのアップデート管理をする必要が出てきます。

よくある理由は以下２点です。
①特定のOS versionでしか動作しない（動作保証していない）アプリケーションを利用しているのでOS Versionは変更できないため
②アップデート時のインターネット向けトラフィック輻輳回避のため

②のトラフィック輻輳ですが、「Microsoftさんが修正するプログラムを送ってくる」≒「インターネット経由でMicrosoftのサーバと通信する」ということになるため、例えばPC×1000台がある会社だと、一気に1000台がインターネット通信を始めてしまいます。そうなると利用者は「Google遅いっ！」、「メール遅いっ！」ってなってしまいます。そうならないようにまずはWSUSが修正プログラムを取得し、WSUSからPCへ修正プログラムを配布することで、インターネットへ出ていく通信量を抑制しています。

【WSUSがない場合】
![スライド3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/3b32f58a-c754-85b7-71ea-0a7187cf3539.png)

【WSUSがある場合】
![WSUS_ある場合.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/53b55891-4a4e-6fe1-b98b-b7117343fc69.png)

# WSUSを利用するためには
WSUSを利用する＝Windows Updateを制御するにはPCがアップデート情報をWSUSから取得するように必要があります。詳しくは別記事で書きますがPCのレジストリ（設定的なもの）を変更し、「アップデート情報はここから取得するように」という方に変更してやる必要があります。PC1台づつレジストリを変更して運用することも出来ますが、一般的にはADの管理機能（グループポリシー機能）でまとめて変更してしまうことが多いと思います。

# WSUSの運用
WSUSは導入後にメンテナンスやチューニングが必要になるサービスです。具体的には定期的な「DBのクリーンアップ」と「DBインデックスの再構成」が必要となります。ほっとおくといつの間にか機能停止やDBのデータ容量がひっ迫するということに陥る可能性があります。こんな感じで”日頃のメンテが重要”なサービスなのですが、設定方法が全然初心者に優しくないです（次回詳細書きます...）

# 参考にしたページ
[そもそもWSUSって何！？WSUSの機能やメリットを分かり易く図解で解説](https://ittrip.xyz/soft/windows/what-wsus)
[WSUSとは？その利点と機能、導入手順をご紹介](https://www.lanscope.jp/trend/10627/)
bashのコマンドプロンプトにCPUの温度を表示させてみる。

#きっかけ
もう２０２１年の年末の話だけど、前回の[ラズパイのケースを自作してみた。](https://qiita.com/SAMisnotMydog/items/73f3c6fcbe4ba427e4a2)で熱対策を全く考えてなかったのでちょっと心配。
実際、訓練中にラズパイがうんともすんとも言わなくなって、熱暴走を疑うことも。

#どうする
別売りでファンが売ってるし温度設定すればで自動的に回るし。。。。ポチッとで解決？

いやいや、<del>ショルコマンド</del>シェルスクリプトの勉強にもなるし、CPUをコマンドプロンプトに表示さえできるようにすれば、CPUの温度が高くなればケースの蓋開ければいいんだし、それでいいんじゃない？

#どうしたら出来る？
1. CPUの温度を知る方法を調べて
1. それをコマンドプロンプトへ反映させる

の２つのことができれば実現出来るかと。
懐かしいなぁ「コマンドプロンプト」だって、MS-DOSでもやった気がするな、config.sysだっけautoexec.batだっけ。。。遠い目。。。

### 1　CPUの温度を知る方法
```bash
pi@samisnotmaydog:~ $ vcgencmd measure_temp
temp=58.0'C
pi@samisnotmaydog:~ $
```
`vcgencmd measure_temp`これはググればすぐ出てきました。
ラズパイって４コアなんだ、おぉコアごとの情報も見れるんだ。。。

<https://qiita.com/kouhe1/items/5f3f0e6fdb55e7164deb>

<https://qiita.com/ksksue@github/items/023f7675faec5d367956>

を参考にいたしました。

### 2 コマンドプロンプトへの反映
まず表示は温度だけでいいよね
いちいち```vcgencmd measure_temp```って入力するの嫌だし
cputemp.shファイルを作って

```bash
#!/bin/bash
vcgencmd measure_temp　 | cut -c 6-
```

```cut -c 6-```で最初の```temp=```をカット
名前もcputempにして実行権限つけて

```bash
pi@samisnotmaydog:~ $ chmod 777 cputemp
```

ﾌﾑﾌﾑコマンドプロンプトにはPROMPT_COMMANDで反映できると、じゃもう出来ちゃったじゃない。

```bash
pi@samisnotmaydog:~ $ PROMPT_COMMAND="cputemp"
```

##なんか違う
```bash
pi@samisnotmaydog:~ $ PROMPT_COMMAND="cputemp"
58.0'C
pi@samisnotmaydog:~ $
58.0'C
pi@samisnotmaydog:~ $
```
リターンごとに温度はアップデートされるのはいいんだけど、２段になってしまう。
おまけに、ターミナルを起動するごとにPROMPT_COMMANDに登録しないといけない
ちょっと違う、これは絶対違う。。。

##.bashrcに書いてしまおう
プロンプトの書式は起動時に.bashrcを読み込んだ際に設定される筈だよね？DOSと一緒だよね？
でも、.bashrcの中は初心者にはナニがナニやら。。。

でもなんとなく、

```bash
if [ "$color_prompt" = yes ];then　
　　　　　　　PS1= 〜ほにゃらら〜
```
のところだよね多分、いや絶対。
```PROMPT_COMMAND``` の他にも　```PS1```を書き換えるとプロンプト変えれるみたいだし
その前に、ターミナルからPS1の値を表示させてみると

```bash
pi@samisnotmaydog:~ $ echo $PS1
\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]($(cputemp)):\[\033[01;34m\]\w \$\[\033[00m\]
```
となったので、多分この何処かに先ほどのcputempの値を表示する変数を挿入するといけそうな気がするな。
この出力のやたら多い```\やら]やら```はエスケープシーケンスの一部らしいから、よくよく読んでみると、そんなに難しいことでも無かったけど、今回はスルー。
こうゆうのが初心者にとってネックだったりするのよね、壁よ壁ね。
以下の記事が大変参考になりました、ありがたいです。

<https://qiita.com/arakaki_tokyo/items/e54d95911ec7a22a7846>

そんでもって、みなさんGitのリポジトリ？、いやブランチを同じようにコマンドプロンプトに表示させておられる様子なので以下の記事を参考にさせていただいてですね。

<https://qiita.com/m-tmatma/items/d9ceba9118d5f6c1be83>

```cputemp``` ではなくて```$(cputemp)```を以下のように仕込んでみたならば

```bash
pi@samisnotmaydog:~ $ PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]($(cputemp)):\[\033[01;34m\]\w \$\[\033[00m\]'
pi@samisnotmaydog(59.6'C):~ $
```
と見事にプロンプトに表示できることが確認できた、ﾔｯﾀｰ。
先ほどの```.bashrc```を開いて、同じように書きこんで確認。

```
pi@samisnotmaydog(63.4'C):~ $
```
これで、いちいち```vcgencmd measure_temp```とか自作の```cputemp```とかを打ち込まなくてもCPU温度が監視できるようになりましたとさ。
##めでたしめでたし
１１月にポリテクセンターに入所して、毎月Qiitaに投稿する目標を立てたものの、訓練所の復習や並行して進めている資格の取得に時間を取られて、当初考えていたペースでは投稿できなくなってしまっているのが実情です。
これも、１１月の終わり頃に実作業はほとんど終えていて、下書きのまま放置してしまっていました。
まだ、ネタはあるので、時間を見つけては投稿するつもりです。
【k8s】minikubeでGitHub Container Registoryのimageを利用する

## はじめに
localのkubernetes環境であるminikubeでGitHub Container Registory
(GitHubが提供しているコンテナレジストリ)からimageを利用する方法について記載する。

## 前提
- GitHub Container Registoryにimageがpushされていること
- minikube環境が動かせすこと

## 手順
手順としてはすごく簡単で以下のコマンドを実行し、k8s sercretを作成し、適用したいdeployment等にimagePullSecretsの設定を加えるだけです。

```shell
kubectl create secret docker-registry regcred --docker-server=ghcr.io --docker-username=<GitHub Container Registory User> --docker-password=<GitHub Container Registory Pass>
```

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
      - name: app 
      ...
      imagePullSecrets:
      - name: regcred
```

## 参考

https://qiita.com/tomoyk/items/5cafe2f43caf80a40aad

https://dev.to/asizikov/using-github-container-registry-with-kubernetes-38fb
[Kotlin]Cookieを扱う(値の設定、取り出し、消去)

#概要
KotlinでCookieを扱うサンプルコードです(値の設定、取り出し、消去)
WebViewや認証処理で活用できると思います。
#本文
```kotlin
package jp.co.cookietest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.webkit.CookieManager
import jp.co.cookietest.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val cookieManager = CookieManager.getInstance()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        val url: String = "https://www.yahoo.co.jp/"
        binding.button1.setOnClickListener {
            Log.w("TAG", "cookieに値を設定します")
            setCookie(url, "count", "15")
        }
        binding.button2.setOnClickListener {
            Log.w("TAG", getCookie(url))
        }
        binding.button3.setOnClickListener {
            Log.w("TAG", "cookieを全て消去します")
            removeAllCookies()
        }
    }

    private fun setCookie(url: String, cookieName: String, cookieValue: String) {
        val cookieString = "$cookieName=$cookieValue;"
        cookieManager.setCookie(url, cookieString)
        cookieManager.flush()
    }

    private fun getCookie(url: String): String {
        return cookieManager.getCookie(url) ?: "cookieは空っぽです"
    }

    private fun removeAllCookies() {
        cookieManager.removeAllCookies(null)
    }
}
```
![スクリーンショット 2022-02-02 21.31.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/e21f0722-0bec-9040-8d82-e2b3a586b728.png)
![スクリーンショット 2022-02-02 21.31.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/7977fea4-bced-de4e-019b-85f04e4872aa.png)
Node.jsでS3に画像をアップロードする。

#Node.jsで画像アップロードする。

```typescript:S3に画像アップロードのサンプル
import S3 from 'aws-sdk/clients/s3'
import fs from 'fs'

const bucket = new S3({
  accessKeyId: process.env.AWS_S3_BUCKET_ID,
  secretAccessKey: process.env.AWS_SECRET_KEY,
})

const fileContent = fs.readFileSync('./images/lisa.png')

const param: S3.Types.PutObjectRequest = {
        Bucket: 'bucketName', // バケット名
        Key: 'lisa.png', // 保存時の画像名
        Body: fileContent,
        ACL: 'public-read', // アクセスコントロール。パブリックアクセスの許可
}

bucket.upload(param, (err: Error, data: S3.ManagedUpload.SendData) => {
  if (err) {
    console.error(err)
  } else {
    console.log('アップロード成功！！！', data)
  }
})

```
中学数学から始めるデータサイエンス

文系エンジニアがデータサイエンスをやるために入社一か月目で学んだこと
初心に返って諸々勉強しました。本当に初心に返って……

# 前提

- 数学IAまでしかやってない
- 治験の統計解析はプログラムをしてたけれど、データの解釈などはわからない。言葉は知ってるけど意味は知らない感じ
- プログラムは好き。数学はニガテ
- Udemyは会社の補助があるので最大限使った。

# 直面した課題
Pythonとかも業務で使ったことなかったけれど、100本ノックやったらなんとなくわかるようになったし、普通に就業していれば困ることはなかった。でも以下の二点だけはどうにも困った。

- **数学の言葉がわからない**
 - 自分が作ったものさえ、何を聞かれているのかがわからないから答えられない。これが本当にしんどい。
 - 数式が読めないと学習効率が落ちる（資料の意味を解釈するのに時間がかかる）
- **「〇〇について、傾向を分析しといて」という課題に全く歯が立たない**
 -  傾向もクソもわからないし、検証すべき課題の仮説すら立てられない
（「Aを正としてモデルを作り、特徴量重要度を出して」という指示ならわかる）

# プログラミング

| 科目 | 記事リンク | 取り組み |
|:-:|:-|:-|
| Python基礎|[]()|[データサイエンス100本ノック](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess)|
| 機械学習入門|[Titanicコンペで機械学習入門](https://qiita.com/Kofuji/items/f5b5cb0ad44e8b811641)|[Kaggle:タイタニック](https://www.kaggle.com/c/titanic)|

# 数学・統計

| 科目 | おススメ教材・資料 |
|:-:|:-|
| 数学基礎|[対数って？なる人向けの記事（たぶん中三～くらいの数学知識）](https://qiita.com/okdysk/items/07f176b26fa9f045e8ef) |
| ベクトル<br>行列<br>線形代数  | [【ゆっくり解説】数学の見え方が変わる 「抽象と具体のベクトル数学 (線形代数)」](https://www.youtube.com/watch?v=dq4mq2ad0xI&feature=youtu.be)<br>・[線形代数とは？初心者にもわかりやすい解説](https://www.headboost.jp/linear-algebra/#1_Part1)|
| 積分  |[【ゆっくり解説】世界を解析する数学「微分積分学」～積分編～](https://www.youtube.com/watch?v=dl8nrr2Fb2g)|
| 微分 |-|
| 確率|[Excel(エクセル)による確率分布基礎講座【確率思考を身につけよう】](https://www.udemy.com/course/excel_probability/)|
| 統計入門| 完全独習　統計学入門（書籍）|

- 学習した内容をまとめた記事がこちら：[数学基礎](https://qiita.com/Kofuji/items/fb24196011eb8a89b708)

- 参考にしたUdemy
    - [いちばん理解できる統計学ベーシック講座その１【確率分布・推定・検定】](https://www.udemy.com/course/statistics_basic/)
    - [いちばん理解できる統計学ベーシック講座その２【相関分析・回帰分析】](https://www.udemy.com/course/statistics_basic_vol2/)
    - [【まだ間に合う！】AI開発・機械学習を理解するための数学講座](https://www.udemy.com/course/math_for_ai/)

# 資料作成

- [テック業界で働く、社会人1年目から知っておきたい「分析の基本的な考え方」- 分割と分解の違い -](https://careerhack.en-japan.com/report/detail/1467)


# モチベ維持や便利ツール

- [非理系出身エンジニアが、数式への抵抗を減らすのに役立ったこと](https://qiita.com/simonritchie/items/a644991dd892e9ddb782)<br>
 └この記事に出会ってなかったらかなりしんどかった。
- [Qiitaの数式チートシート](https://qiita.com/PlanetMeron/items/63ac58898541cbe81ada)<br>
 └数学を学ぶのと記事にするのをセットにしていたので、記事を書くとき重宝した
- [GeoGebra](https://www.geogebra.org/)<br>
 └グラフを書くのに超絶便利

# 所感
数学の苦手意識が軽減した。とりあえずまだクビにはなってないので、来月も頑張りたい
Heroku CLIでSyntaxError ~ Unexpected end of JSON input が発生。

# はじめに
**先日HerokuにLINEボットをデプロイしました。**
まだ完成していませんが、初めてボットをデプロイしたのでウキウキです。
Heroku CLIをインストールしたときに発生したわけのわからぬエラーが無ければ。


# 環境
`heroku --version`

- Linux (KDE neon 5.23.5)
- heroku/7.59.2 linux-x64
  - スタンドアロンインストール
- node-v12.21.0

# 課題
**謎のSyntax errorが発生しています。**
エラーの内容は以下の通り。

```
heroku config -a {app name}
(node:xxxx) SyntaxError Plugin: heroku: /home/Your name/.local/share/heroku/config.json: Unexpected end of JSON input
module: @oclif/config@1.13.2
task: runHook prerun
plugin: heroku
root: /usr/local/lib/heroku
See more details with DEBUG=*
```

はい、わけがわかりません。
ただこのエラーの不思議な点は、エラーが出ても普通に使えているというところです。
普通エラーが出たら処理が中断されそうなもんですが、コマンドも普通に実行されるんですよね。


# 原因
**Herokuのconfif.jsonの中身が空であったことが原因でした。**
はい。上記エラーで示された場所にHerokuのconfig.jsonがあるのですが、どうもその中身が空（文字通り中身何もなし）の場合、このエラーが出るようです。
jsonファイルなのにjsonらしい記述が何もないとだめなんですかね。
とりあえず、このjsonを正常な形に戻してやれば解決するみたいです。
**config.jsonがない場合は、新しく作ってやればいいみたい。**

# 解決策
**config.jsonに波括弧{}を加えるだけです。**
エラー文にconfig.jsonの場所が示されているので、それを頼りに`vi config.json`します。
あとは波括弧を適当に加えるだけでいいです。例えばこんな感じ。

```
{

}
```

これだけで本当に解決しちゃうんですから、楽なもんですね。


# おわりに
超絶簡単な解決でした。
いつもこれくらい簡単にエラーが解決してくれたらいいんですけど……。
とりあえずこれで気持ち悪いエラーが消えたので、スッキリした気持ちでLINEボットを作成できます。
やったぜ。

# 参考
ちなみに今回の解決法以外に、`heroku login` をインタラクティブでやるっていう解決法が提示されていたのですが、自分はそちらでは解決しませんでした。

https://github.com/heroku/cli/issues/1222
Remixで作成したコントラクトをEtherscanで検証する方法の備忘録

## Remixと、Etherscan紹介

[Remix](https://remix.ethereum.org/)はEthereumのIDEです。ブラウザ上でスマートコントラクトの開発を行うことができます。[こちらの記事](https://qiita.com/taijusanagi/items/9ce63d64c9f5b4d6b66e)に使い方をまとめています。

[Etherscan](https://etherscan.io/)はEthereumのブロックエクスプローラーです。Etherscanでは開発したスマートコントラクトのソースコードを検証し、公開することができます。

今回の記事では、Remixのプラグインの一つであるEtherscanの検証機能を使用します。EtherscanのAPIキーを使用しますので、APIキーを持っていない人は[こちらの手順](https://qiita.com/taijusanagi/items/c34d14767feeb3e131a8)で取得してください。

また、こちらのコントラクトの検証は、コントラクトをデプロイした後に行います。

## Etherscan - Contract Verification

左下のプラグインアイコンをクリックし、Plug inの中からEtherscan - Contract VerificationをActivateします。

![Screen Shot 2022-02-02 at 21.01.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/336d57f8-606b-d553-52dd-f2f27bc1c190.png)

新しく追加されたEtherscanのアイコンをクリックし、EtherscanのAPIキーを保存します。

![Screen Shot 2022-02-02 at 21.03.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/3cf80478-2eee-2d1c-45de-c27b14ee8ac3.png)

対象のコントラクトを選択し、デプロイしたContract Addressを入力します。

![Screen Shot 2022-02-02 at 21.04.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/c438425a-7835-3b2d-c3ea-d252fc6ca54c.png)

検証に成功すると下記のようにEtherscanで検証済みのマークが記載され、ソースコードを確認することができます。今回検証に使用したコントラクトは[こちら](https://rinkeby.etherscan.io/address/0x334995575a42cc36dfc2c83cd53ee02fa8fe76bf#code)です。

![Screen Shot 2022-02-02 at 21.06.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/ef98d886-d8ba-6895-708d-d125e6530cb2.png)

作ったNFTを検証して公開してみよう、という際にもとても便利な機能なので、ぜひ使ってみてください！