OmniAICreator/Qiita-1.07M huggingface dataset:
Ray ClusterをKubernetes上で試す

# Rayとは

https://www.ray.io/

Pythonを簡単にスケールできるようにするオープンソースプロジェクト

- Deep Learning
- Reinforcement Learning
- Hyperparameter Tuning
- General Python apps
- Model Serving
- Data Processing

MLがメインのようにみえるが、様々な用途に使える。

# Ray-operator

RayをKubernetes上で動かすためのOperatorがある

Custom Resource: `RayCluster`

https://github.com/ray-project/kuberay/tree/master/ray-operator


# ステップ

## インストール

```
kubectl apply -k "github.com/ray-project/kuberay/ray-operator/config/default"
```

## Rayクラスタ作成


`RayCluster`の作成

```
kubectl apply -f https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/ray-cluster.heterogeneous.yaml
```

`ConfigMap`の作成
```
kubectl apply -f https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/config-map-ray-code.yaml
```

ConfigMapに、Pythonのコードが入っている

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: ray-code
data: 
  sample_code.py: |
    import ray
    from os import environ
    redis_pass = environ.get("REDIS_PASSWORD") 
    print("trying to connect to Ray!")
    ray.init(address="auto", _redis_password=redis_pass)
    print("now executing some code with Ray!")
    import time
    start = time.time()
    @ray.remote
    def f():
      time.sleep(0.01)
      return ray._private.services.get_node_ip_address()
    values=set(ray.get([f.remote() for _ in range(1000)]))
    print("Ray Nodes: ",str(values))
    file = open("/tmp/ray_nodes.txt","a")
    file.write("available nodes: %s\n" % str(values))
    file.close()
    end = time.time()
    print("Execution time = ",end - start)
```

確認: `head` 1つと`worker`が4つ動いている

```
kubectl get pod
NAME                                                 READY   STATUS    RESTARTS   AGE
raycluster-heterogeneous-head-72l7l                  1/1     Running   0          2m31s
raycluster-heterogeneous-worker-medium-group-zcml2   1/1     Running   0          2m31s
raycluster-heterogeneous-worker-small-group-fvxd5    1/1     Running   0          2m31s
raycluster-heterogeneous-worker-small-group-hrlt7    1/1     Running   0          2m31s
raycluster-heterogeneous-worker-small-group-nkqj8    1/1     Running   0          2m31s
```

# 参考
- https://towardsdatascience.com/modern-parallel-and-distributed-python-a-quick-tutorial-on-ray-99f8d70369b8
- https://github.com/ray-project/kuberay
- https://ray-project.github.io/2018/07/15/parameter-server-in-fifteen-lines.html
- https://github.com/apache/arrow/blob/master/cpp/apidoc/tutorials/plasma.md#:~:text=Plasma%20clients%20are%20processes%20that,once%20they%20have%20been%20created.
W: GPG error: http://apt.postgresql.org/pub/repos/apt stretch-pgdg InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY xxx

# Error

```
sudo apt update
...
Get:10 http://apt.postgresql.org/pub/repos/apt stretch-pgdg InRelease [81.6 kB]                       
Err:10 http://apt.postgresql.org/pub/repos/apt stretch-pgdg InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY XXXXXXXXXXXXXX
Reading package lists... Done 
W: GPG error: http://apt.postgresql.org/pub/repos/apt stretch-pgdg InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY XXXXXXXXXXXXXX
E: The repository 'http://apt.postgresql.org/pub/repos/apt stretch-pgdg InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
```

# 解決方法

```
nakamasato@xxxx:~$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys XXXXXXXXXXXXXX
Executing: /tmp/apt-key-gpghome.zfSr40cnbr/gpg.1.sh --keyserver keyserver.ubuntu.com --recv-keys XXXXXXXXXXXXXX
gpg: key XXXXXXXXXXXXXX: 6 signatures not checked due to missing keys
gpg: key XXXXXXXXXXXXXX: public key "PostgreSQL Debian Repository" imported
gpg: Total number processed: 1
gpg:               imported: 1
```

# References
- https://itsfoss.com/solve-gpg-error-signatures-verified-ubuntu/
- https://pyopyopyo.hatenablog.com/entry/20180514/p1
[VScode_Remote Containers] コンテナ環境内でデバッグする(Mac)

# リポジトリ

[https://github.com/melumuccu/python-openpyxl](https://github.com/melumuccu/python-openpyxl)

# 概要

## この記事でやれること

- VScodeの `Remote Containers` を使った**ローカル環境を一切汚さずデバッグができる環境**を作れる

# 環境

|  | バージョン | memo |
| --- | --- | --- |
| Python | 3.10.4 |  |
| OpenPyXL | 3.0.9 | Excel ファイルを Python で扱うためのパッケージ |
| Docker | 20.10.11 |  |
| Visual Studio Code | 1.66.2 |  |
| Remote Containers | 0.234.0 | VScode 拡張。コンテナ内で VScode を動作させる(?)。デバッグなどの目的で導入。 |

# 環境構築

## 前提環境: 前記事を利用

[[Python×Docker×OpenPyXL] Excelファイルを扱うDocker環境構築(Mac) - Qiita](https://qiita.com/sawa-akabee/items/e2b29ce19682caf7f091)

- 上記記事のdocker run コマンドが正常に動作する前提とします

## VScodeにRemote Containers拡張機能を導入

- 識別子: ms-vscode-remote.remote-containers

## Remote Containersの設定

- `.devcontainer/devcontainer.json` にDockerfileのパスやコンテナ内のVScodeにインストールする拡張機能などを指定
    - 前提環境では下記のようになっている

```json
{
  "name": "Python IO",
  // Dockerfileでイメージ・コンテナを作成
  "dockerFile": "../Dockerfile",
  // リモート先のVS Codeにインストールする拡張機能
  "extensions": [
    // Python系
    "ms-python.python",
    "ms-python.vscode-pylance",
    "kevinrose.vsc-python-indent",
    "dongli.python-preview",
    "njpwerner.autodocstring",
    // その他Util
    "nemesv.copy-file-name"
  ],
}
```

- 下記は必須(デバッグ実行に必要なはず)
    - "ms-python.python"
    - "ms-python.vscode-pylance"

## Remote Development でコンテナに入る

- 下記画像の順にクリック
    - (VScodeの左下にあるボタン)
    
![RemoteDevelopment_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/eb02927e-e089-dc83-1ce8-3e23408412bc.png)
    
    ---
    
![RemoteDevelopment_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/dbccbf1e-f4c7-49a0-186b-1a7790591ea8.png)

    ---
    
![RemoteDevelopment_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/4bb00bd6-3ba2-5300-bbbb-b9e74c400f69.png)



## sample.py を開き VScode から実行する

- 実行のみでも、ソースの行をクリックしてブレークポイントを仕掛けてデバッグ実行でも

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/24a7b030-487e-4a0f-a98d-cb1bf603565c.png)
native-base Flexの「Invalid YGDirection 'row' should ....」エラーについて

# error内容
![スクリーンショット 2022-05-14 15.31.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/957847/db888834-cc52-1121-a0d5-f5a21d809397.png)

# 原因
```tsx
import { Flex } from 'native-base'

// ...

  return (
    <Box pb={60}>
      <Flex
        direction={'row'} // 原因
        // ...
      >
        {/* contents */}
      </Flex>
    </Box>
  )
```

# 解決
```tsx
import { Flex } from 'native-base'

// ...

  return (
    <Box pb={60}>
      <Flex
        flexDirection={'row'} // direction => flexDirection へ
        // ...
      >
        {/* contents */}
      </Flex>
    </Box>
  )
```

## 参考
https://stackoverflow.com/questions/60479653/invalid-ygdirection-row-should-be-one-of-inherit-ltr-rtl-react-native
Vue.jsでslotを使う

## slotとは

  コンポーネントの呼び出し元で指定したコンテンツをテンプレートに埋め込むことができる機能のこと。

## slotの基本構文

呼び出し元の書き方

```vue
<div id="app">
  <my-component>呼び出し元の文字列</my-component> <!-- "呼び出し元の文字列"が"my-component"に差し込まれる -->
</div>
```

呼び出し先のcomponentの書き方

```jsx
Vew.create({})
  .component('my-component', {
    template: `<div>これは、<slot>呼び出し先の文字列</slot></div>`
  })
  .mount('#app')
```

呼び出し元から差し込まれた文字列が＜slot＞〜＜/slot＞の間に差し込まれる。

「呼び出し先の文字列」は、呼び出し元からの入力がなかった場合に表示されるデフォルト値。

## Slotのスコープ

slotにはvue.jsで使用される”{{}}”(口髭構文)、式などを含めることができる。が、あくまで”呼び出し元のデータ属性や式にアクセスできる”というだけであって、呼び出し先のデータを期待してそれを使用することはできない。以下はslotを利用できない例。

呼び出し側

```html
<div id="app">
	<my-component>{{ coment }}</my-component> <!-- 呼び出し先で定義されているであろう”coment”を表示しようとしている -->
</div>
```

呼び出し先

```jsx
Vue.create({})
  .component('my-component', {
    data: {
      return {
	    coment: 'コメントです'
      }
    }
  })
  .mount('#app')
```

slotを利用する場合はあくまで呼び出し元のデータを利用する。

## 複数のslotを同時に利用する

“template”を利用して同じ呼び出し先に複数のslotを登録することができる

呼び出し元

```html
<div id="app">
  <my-component>
	  
    <template v-slot:header>
      <h1>ヘッダーです</h1>    <!-- 呼び出し先で'header'という名前で呼び出すことができる -->
    </template>

    <p>名前なしのスロット</p>    <!-- これもslot(名前を指定していないだけ) -->
    
    <template v-slot:footer>
      <h1>フッターです</h1>    <!-- 呼び出し先で'footer'という名前で呼び出すことができる -->
    </template>
  
  </my-component>
  
</div>
```

上記の場合3つのslotを設定している。”v-slot:slot名”とすることでslotの種類を判別できるようにしている。わかりずらいがpタグの行は名前を指定していないデフォルトのslot。混在させて書くことが可能。

呼び出し先

```jsx
Vue.create({})
  .component('my-component', {
    template: `<div>
                 <header>
                   <slot name="header">ヘッダーです</header> // v-slot:headerがここに差し込まれる
			     </header>

                 <slot><名前なしのスロット/slot>  // 名前を指定していないスロットがここ差し込まれる（今回の場合はpタグ）

                 <footer>
                   <slot name="footer">フッターです</slot>
                 </footer>
                </div>`
  })
  .mount('#app')
```

呼び出し元では”<slot name=”定義したスロット名”>”という形で作成したスロットを呼び出すことができる（呼び出す順番は呼び出し先で指定できるので、呼び出し元では順番を気にする必要はない）
Python set型の取扱い 備忘録

## 概要
set型はlist型よりも演算が早いので使う場面が多いが、集合には少し注意が必要と感じたので備忘録として残す。
setの基本的な使い方は下記リンクを参照のこと。

https://note.nkmk.me/python-set/

- 実施期間: 2022年5月
- 環境：Colab (Python3)

## 集合
使用する集合は下記とする。

```python
set0 = {i for i in range(11)}
set1 = {1, 2, 3, 6, 7}
set2 = {3, 4, 5, 7, 8}
set3 = {6, 7, 8, 9, 10}
```
ベン図で書くとこんな感じ。
![Screenshot from 2022-05-14 11-49-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/2ca872a9-52be-6130-246a-6b9eecf24266.png)

## 和集合
|演算子かunion()で求める。
set1,2と、set1,2,3の和集合は下記となる。

```python
print(set1 | set2)    # または
print(set1.union(set2))
>>> {1, 2, 3, 4, 5, 6, 7, 8}

print(set1 | set2 | set3)    # または
print(set1.union(set2,set3))
>>> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
```
set1,2の和集合をベン図で太字で書くとこんな感じ
![Screenshot from 2022-05-14 14-11-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/c13a5cac-23ca-149d-c618-f25a9dbaaae5.png)

## 積集合
&演算子かintersection()で求める。
set1,2と、set1,2,3の積集合は下記となる。

```python
print(set1 & set2)    # または
print(set1.intersection(set2))
>>> {3, 7}

print(set1 & set2 & set3)    # または
print(set1.intersection(set2,set3))
>>> {7}
```

set1,2の積集合をベン図で太字で書くとこんな感じ
![Screenshot from 2022-05-14 14-10-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/58d2fcaf-ba3e-3672-b716-c9cad09c4a37.png)

## 差集合
-演算子かdifference()で求める。**差なので順番により答えは異なる。**
set1,2と、set2,1の差集合は下記となる。

```python
print(set1 - set2)    # または
print(set1.difference(set2))
>>> {1, 2, 6}

print(set2 - set1)    # または
print(set2.difference(set1))
>>> {8, 4, 5}
```
set1,2と、set2,1の差集合をベン図で太字で書くとこんな感じ
![Screenshot from 2022-05-14 14-21-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/aaf103eb-d69a-aabf-161f-cd34737ad06d.png)

## 対称差集合
^演算子かsymmetric_difference()で求める。
まず、^演算子を使ったset1,2の対称差集合は下記となる。

```python
print(set1 ^ set2)
>>> {1, 2, 4, 5, 6, 8}
```
![Screenshot from 2022-05-14 14-33-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/abcc39dd-19f4-98f9-01b7-069a73652f6f.png)

重なっていた{3, 7}が除かれた結果となる。
では、set1^set2^set3はどうなるのか？３集合間で重なった{3, 6, 7, 8}が除かれるわけではない。

```python
print(set1 ^ set2 ^ set3)
>>> {1, 2, 4, 5, 7, 9, 10}
```
![Screenshot from 2022-05-14 15-00-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205257/c06cd8df-cad9-4fca-98d8-0de6e3f5c7c3.png)
先に求めたset1^set2の対称差集合{1, 2, 4, 5, 6, 8}に対し、再度set3で対称差集合を求めたものになった。
こんな計算に意味があるのか疑問なので、**対称差集合には２変数だけを使用すべきだと思う。**
Pythonにそういった思いがあるのか下記はエラーとなる。symmetric_difference()だけには２変数以上は渡せない。

```python
print(set1.symmetric_difference(set2, set3))
>>> TypeError: symmetric_difference() takes exactly one argument (2 given)
```

https://www.pandanoir.info/entry/2016/12/01/001733

以上
【CSS Tips】:visitedに指定した色が効かないと思ったら、アルファチャンネル（色の透明度）が原因だった

## これは何

aタグの`:visited`に色を指定したのに効かなかった時に調べてもパッと答えが出てこなかったので記録しておきます。

## 効かなかった理由

ズバリ指定している色に`アルファチャンネル`を指定していたからでした。

MDNを見ると以下のように記載されています。

> 利用できるスタイルでもアルファチャンネルは無視されます。アルファチャンネルは要素の :visited 状態ではないものが代わりに使用されますが、アルファチャンネルが 0 であった場合は、 :visited で設定されたスタイルセットは全体的に無視されます。

https://developer.mozilla.org/ja/docs/Web/CSS/:visited

私が詰まっていた時は

デフォルト時： `rgba(0, 0, 0, 0.87)`
`:visited`の時： `rgba(0, 0, 0, 0.6)`

のように色を指定していました。

```css
/* こんな感じ */

.textlink {
  color: rgba(0, 0, 0, 0.87);
}
.textlink:visited {
  color: rgba(0, 0, 0, 0.6);
}
```

この時`:visited`で指定されているアルファチャンネル`0.6`が無視されて全体の`0.87`が採用されます。
さらに指定しているRGB値は同じだったため、結果としてリンク訪問前後で色が変わらないようになっていました。

## 解決策

`:visited`ではアルファチャンネルを使わない色に置き換えて指定すれば色が変わります。
Ansible: fluent-bitの設定

## 概要
Ansibleを使ってfluent-bitをRaspberryPiにインストールします。


## プレイブックとテンプレート
マニュアルに書かれている通り、GPG鍵を登録してapt経由でインストールします。

```yaml:fluent-bit.yaml
- name: Setup fluent-bit 
  hosts: all
  become: true
  gather_facts: false
  tasks:
    - name: Add fluent-bit server’s GPG key
      ansible.builtin.apt_key:
        url: https://packages.fluentbit.io/fluentbit.key 
        state: present

    - name: Add fluent-bit repository into the sources list
      ansible.builtin.apt_repository:
        repo: deb https://packages.fluentbit.io/raspbian/bullseye bullseye main
        state: present

    - name: Install fluent-bit
      ansible.builtin.apt:
        name: fluent-bit
        update_cache: true

    - name: Upload a configuration file
      ansible.builtin.template:
        src: fluent-bit.conf.j2 
        dest: /etc/fluent-bit/fluent-bit.conf
        mode: "0644" 
      notify:
        - config is updated

  handlers:
    - name: Restart fluent-bit
      ansible.builtin.systemd:
        name: fluent-bit
        state: restarted 
      listen:
        - config is updated

  post_tasks:
    - name: Ensure fluent-bit is enabled and started
      ansible.builtin.systemd:
        name: fluent-bit 
        state: started
        enabled: true
```


設定ファイルのテンプレート下記の通りです。タグにホスト名を追加しています。

```jinja:templates/fluent-bit.conf.j2 
[SERVICE]
    # Daemon
    # ======
    # instruct Fluent Bit to run in foreground or background mode.
    #
    daemon       Off

[INPUT]
    name cpu
    tag  {{ inventory_hostname_short }}.cpu
    # Read interval (sec) Default: 1
    interval_sec 1

[OUTPUT]
    name  stdout
    match *
```

## 参考
- [Raspbian / Raspberry Pi - Fluent Bit: Official Manual](https://docs.fluentbit.io/manual/installation/linux/raspbian-raspberry-pi)
gpgコマンド


## gpg コマンドのメモ

使用頻度が低くて思い出せないので書き出しておく

　

### 使用例

#### [非対話形式] a.txt を暗号化する (パスワードは「password」)

a.txt.gpg が生成される

```bash
$ echo "password" | \
    gpg --batch --passphrase-fd 0 --symmetric --cipher-algo AES256 a.txt
```

　

#### [非対話形式] a.txt.gpg を解読する (パスワードは「password」)

```bash
echo "password"|gpg --batch --passphrase-fd 0 --decrypt a.txt.gpg
```

　

#### 対話形式で実行したい場合

上記から「--batch --passphrase-fd 0」を削除して実行すれば良い
[Python×Docker×OpenPyXL] Excelファイルを扱うDocker環境構築(Mac)

# リポジトリ

[https://github.com/melumuccu/python-openpyxl](https://github.com/melumuccu/python-openpyxl)

# 概要

## 今回のリポジトリを作ろうとしたきっかけ

- 投資で仮想通貨の取引を行っている
    - 取引記録を取引所からExportしたときに、**一つの注文に対してほぼ同時に複数の約定が起こり取引記録が複数に分裂することが多々起こった**ため、それらの取引履歴を一つにまとめたいと思った
        - 手作業でやるのは流石にしんどいので、Pythonで自動化するか！

って感じです

## この記事でやれること

- Python と OpenPyXL によるExcelファイル操作を行うDockerコンテナを作れる
- ついでに、VScodeの `Remote Containers` を使った**ローカル環境を一切汚さずデバッグができる環境**を作れる
    - (別記事にしました https://qiita.com/sawa-akabee/items/0199dac0320203f13d8e)

## 挙動

### 1コマンドでコンテナ起動〜処理〜コンテナ破棄

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/dd506ea8-0cd0-0885-2f1d-4f2b56983774.gif)


- コンテナ起動(docker run) からのフローは下記となる
    - docker run
    ⇒ 環境変数でExcelファイルのパスを渡したコンテナ内でExcelファイルが処理される
    ⇒ 処理終了後、コンテナが自動で破棄される

この挙動により、一度環境を構築してしまえば1コマンドでExcelファイルが処理され、無駄にコンテナが残ることもありません

# 環境

|  | バージョン | memo |
| --- | --- | --- |
| Python | 3.10.4 |  |
| OpenPyXL | 3.0.9 | Excel ファイルを Python で扱うためのパッケージ |
| Docker | 20.10.11 |  |
| Remote Containers | 0.234.0 | VScode 拡張。コンテナ内で VScode を動作させる(?)。デバッグなどの目的で導入。 |

# 環境構築

## 前提

- ここでは”src/sample.py”を利用している想定とします

## 手順

### clone

- リポジトリから任意のディレクトリにclone

```html
$ git clone ~~~
```

※以降、このcloneしたディレクトリでコマンドを実行するものとしてます

### image をビルドする

```html
$ docker build --tag py-file-io .
```

※imageが作成されたことを確認し、image id をコピーしておく

```html
$ docker images -a

REPOSITORY  TAG       IMAGE ID       CREATED             SIZE
py-file-io  latest    8027ef8d5630   About an hour ago   1.03GB
```

### コンテナ起動=>処理実行=>コンテナ破棄

```html
$ docker run -it --rm \
-v $(pwd)/src:/root/src \
-v $(pwd)/input:/root/input \
-v $(pwd)/output:/root/output \
[py-file-ioのimage ID]
```

<details><summary>オプションについて</summary>

- --rm
    - コンテナがstopされた時にコンテナを破棄するオプション
        - コンテナ起動時にDockerfileのENTRYPOINTにかかれているコマンドが実行され、そのコマンドの処理が終了した時点でコンテナはstopされる
- -v
    - ボリュームを指定するオプション(ローカル:コンテナ)
</details>

<details><summary>(より詳しく)この時何が行われているか？</summary>

1. ボリュームの指定により、ローカルの/src と コンテナ環境の /root/src が共有される(他inputなども同様)
2. docker run に image IDを渡しているので、そのimageでコンテナが作成される
3. image作成に使用したDockerfileには
    - ENTRYPOINTが指定されてるので、コンテナ作成後ENTRYPOINTのコマンドが起動する
        - ⇒ /root/src/sample.py が Pythonで実行される
        - WORKDIRは /root/src と指定してある
4. /root/src/sample.py は /root/input 内にあるファイルを1つずつ処理し /root/output に格納していく
5. /root/src/sample.pyの処理が終わるとコンテナはstopされる
6. --rm オプションを付けてコンテナを起動していたのでコンテナは破棄される
7. /root/output はローカルの/outputにマウントされていたので、/root/output に格納されていた 出力ファイルはコンテナが破棄されていてもローカルの /output に残っている
</details>
    

## 結果

- input/sample.xlsx のファイルを処理して /output/sample.xlsx が生成される
- 以降はdocker runコマンドのみで処理を起動できる

# この環境を使って異なる処理を実装する場合のデバッグ環境の作り方

今回の/root/src/sample.py の処理は完全に自分用のニッチな処理なので、この環境を使って別の処理を書きたいということがほとんどな気がします。

なので、実際に自分がこの機能を開発したときのデバッグ環境として利用した**VScode拡張のRemote Containers**の使い方を別記事に書きました！

https://qiita.com/sawa-akabee/items/0199dac0320203f13d8e
Wireguardを有効化するとインターネットに繋がらなくなるときの対処法 （デフォルトルートがおかしくなる）

Wireguardは素晴らしいソフトウェアですが一つだけ初見殺しな仕様があります。

### 前提条件
**VPN経由でインターネットに接続したいのではなくあくまでもサーバー間の通信としてVPNを使用したい。**
```
eth0 (インターネット )          eth0 (インターネット)
 ↕                              ↕
サーバーA ← wg0 (vpn) wg0 → サーバーB
```

<br>


### 症状
・Wireguardを有効にするとインターネットに繋がらなくなる <br>
・無効化すると戻る <br>
・`ip route`でデフォルトルートを調べてもちゃんと`eth0`など本来のインターフェイスが設定されている

### 対処法
まず`ip route get 1.1.1.1`を実行してみる。すると驚くべきことに`ip route`ではeth0がデフォルトになっているのに`wg0`経由になっている。<br>

```
suser@localhost:~> ip route
default via 192.168.0.1 dev eth0 proto dhcp [←ちゃんとeth0がデフォルトルートなのに]
10.0.0.0/24 dev wg0 proto kernel scope link src 10.0.0.2 
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.200 

suser@localhost:~> ip route get 1.1.1.1
1.1.1.1 dev wg0 table 51820 src 10.0.0.2 uid 1000  [←何故かwg0経由になっている]
    cache 
```
<br>
実はこれWireguardの仕様らしい。こんなん気づく訳ないやろという感じですが仕様なので仕方ありません。<br>
しかし対処法は簡単なのでご安心ください。<br><br>

`/etc/wireguard/wg0.conf` に `Table = off`を追加するだけです。<br>
<br>

`sudo nano /etc/wireguard/wg0.conf`
<br>

```
[Interface]
Address = 10.0.0.2/24
ListenPort = ポート
PrivateKey = 秘密鍵
Table = off [←これを追加する]


[Peer]
PublicKey = 公開鍵
PresharedKey = 事前共有鍵（任意）
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = サーバーのIP:ポート
PersistentKeepAlive = 30
```

<br>

後は`sudo systemctl restart wg-quick@wg0`なり何なりで再起動して変更を適用しましょう。
ifMozilla ifSafari とか

## CSSもブラウザ別に処理させたいこともきっとあります。

```ifIE.scss
@mixin ifIE() {
	@media all and (-ms-high-contrast: none) {
		@content;
	}
}
```

```ifEdgeHTML.scss
@mixin ifEdgeHTML() {
	@supports (-ms-ime-align: auto) {
		@content;
	}
}
```

```ifedge.scss
@mixin ifEdgeHTML() {
	@supports (not (-webkit-hyphens: none)) and (not (-moz-appearance: none)) {
		@content;
	}
}
```

```ifwebkit.scss
/* Webkit Chrome, Opera, Safari */
@mixin ifWebkit() {
	@media screen and (-webkit-min-device-pixel-ratio:0) {
		@content;
	}
}
```

```ifchrome.scss
/* Chrome, Opera */
@mixin ifChrome() {
	@media screen and (-webkit-min-device-pixel-ratio: 0) and (min-resolution: .001dpcm) {
		@content;
    }
}
```

```ifmozilla.scss
@mixin ifMozilla() {
	@-moz-document url-prefix() {
		@content;
	}
}
```

```ifsafari.scss
/* Safari まだ未完成 */
@mixin ifSafari() {
	@supports (paint-order: fill) and (-webkit-marquee-speed: 0) {
		@content;
	}
}
```

### ifsafari 以外は動きます

メジャーなブラウザだけをサポートするという前提で
safari用のCSSを記述するには、以下のようにします

```
// @include ifSafari() { //コメントアウトが書いてあることが大事
     safariのCSS
//}

   @include ifMozilla() {
     mozillaのCSS
   }

   @include ifwebkit() {
     webkitのCSS
   }

   @include ifEdgeHTML() {
     edgeHTMLのCSS
   }
```
kubectl をインストールする

https://github.com/kubernetes/kubernetes/releases を見てインストールしたいバージョンを特定する。

ここでは v1.22.9 とする。

```
$ version=v1.22.9
$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/${version}/bin/linux/amd64/kubectl"
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl
```

インストールしたバージョンの確認

```
$ kubectl version --client
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.9", GitCommit:"6df4433e288edc9c40c2e344eb336f63fad45cd2", GitTreeState:"clean", BuildDate:"2022-04-13T19:57:43Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}
```
Node.js自分用のまとめ

この記事は自分で見直す用に残しておく

Node.jsについて
ブラウザでしか動けないJavascriptをパソコン上で動かせるようにするためのもの、すなわちJavascripｔの実行環境である。

これを使うとOＳ機能にアクセスするプログラムを作成することができる。なので、ファイルの読み書きやネットワーク通信などのＯＳの機能がさわれるようになる。

Node.jsを使用する目的
・新しい仕様のjavascript＆Typescriptでプログラムを書くため
・webアプリケーションを作りたい
・モバイル/デスクトップ用のアプリケーションを作りたい
などっぽい

とりあえずは、React＆TypeScript使用していくので今後学びがあれば自分用にまとめるようにする。
STM32G031でRS-485パケットで超音波距離センサーの値を読み込みたい(送信テスト


目的
RS-485で上り下りの実現
複数話になる
どこまで行けるかわからないが作ってみよう

いちお、データ4バイト　オール0で読み込み　と　する。


とりあえず



```c++


//ser_500kbps_HC-SR04_M_test_031_1

// tx PA14(PB6) 8PIN
// rx PC14(PB7) 1PIN

#include <Arduino.h>


void ultrasound(char id){

  int ii;           //カウンター
  char out_buff[8]; //バッファー

  //バケットに値を設定
  // packet move
  out_buff[1 - 1] = 0x00; //header
  out_buff[2 - 1] = 0x40+id; //address
  out_buff[3 - 1] = 0x00; //data1  zero Fixed
  out_buff[4 - 1] = 0x00; //data2  zero Fixed

  out_buff[5 - 1] = 0x00; //data3  zero Fixed
  out_buff[6 - 1] = 0x00; //data4  zero Fixed
  out_buff[7 - 1] = 0x00; //Checksum
  out_buff[8 - 1] = 0xff; //footer

  //チェックサムの計算
  //Checksum
  int chk = 0;
  for (ii = 0; ii < 8; ii++) {
    chk = chk + out_buff[ii];
  }//for
  out_buff[7 - 1] = chk & 0xff;

  //送信処理
  //send 8 byte
  delay(1);
  for (ii = 0; ii < 8; ii++) {
    Serial.write(out_buff[ii]);
  }//for
  delay(1);

} //pc_putc

//初期化処理
void setup() {

  delay(3000); //not Delete

  Serial.begin( 500000 ); // シリアル通信の速度を500000bpsにする。

} //setup


//メインループ
void loop() {

  ultrasound(0); //ID 0

  delay(1000);

}//loop



```
[C#] ChainingAssertion-MSTests.Bin を参照しましょう

# 環境と事の始まり
## 環境
IDE：Visual Studio 2022
NuGet：ChainingAssertion-MSTests.Bin  ←最終的に
## 事の始まり
ピーコック・アンダーソンさんのドメイン駆動開発のBlog記事を見て、「これはやらねば。試してみよう！」と、写経していたところ、NuGetで「Chaining Assertion」を入れているのに、下記の Isメソッドが有効になってくれず、あれこれ迷走した。  
```
vm.AreaIdText.Is("0001");
```

https://anderson02.com/cs/nddd/nddd-01/

# 解決方法
NuGetで「ChainingAssertion」をインストールするのではなく、「ChainingAssertion-MSTests.Bin」をインストールすると良い。

---
自分自身の知識で原因がわかっていない点はどうかと思うが、とりあえず先に進めるので良しとする。
【C++】Segment Tree の実装

# 何の記事か

今回はセグメント木(Segment Tree)というデータ構造について、勉強したことをまとめてみた。
参考書として使ったのは蟻本。だいだい内容は同じだ。
概要、それらを使ってできること、実装の順で説明してある。

# セグメント木
## 何それ
セグメント木は具体的に以下の画像のようなデータ構造になっている。
![seg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/50b4870c-eb4c-2efa-4dc6-38262e62a9e0.png)
それぞれの要素は、対応する数列の区間の何かしらのデータを管理している。
構造的には完全二分木になっているので、$O(logN)$で動作する高速なデータ構造を実現できる。

解きたい問題における数列を{$a_i$}とすれば、{$a_i|i=s～t$}に対して求めたいある値を$O(logN)$で求めることができるというわけである。
今回は **RMQ(Range Minimum Query)** を解くことを考えることにする。
つまり、『{$a_i|i=s～t$}の最小値を求めるクエリを高速に処理する』ことを考えるために、セグメント木を用いることにする。

:::note warn
RMQ
数列のある区間に対して、その中の要素の最小値を求めるクエリのこと。
:::

## できること

数列 {$a_i$}が与えられたときに、以下の操作を$O(logN)$で行うことができる。
- $s$と$i$が与えられた時、{$a_i|i=s～t$}の最小値を求める
- $a_i$の値を更新する

では本当にこれらの操作を$O(logN)$で行えるのだろうか。
図を見てもらった方が分かりやすいと思うので、図を描いてみた。今回のセグメント木のデータ数は$2^4$としてある。
![seg2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/ab88f2f2-fe9d-3c9d-5fdd-d64ffaa4a597.png)
最小値を求める操作では、普通に解こうとすると、$O(N)$となってしまうことは自明だろう。
しかし、セグメント木を用いた解法では、図のように『予め最小値を求めておいた区間』を利用することで、一回の参照でも大部分の処理を行うことができている。
具体的には $t-s$ を、できるだけ大きい$2^x$から順にみていく操作になっているので、計算量が$O(logN)$となるわけである。

値を更新していく操作は、子から親へとどんどん値を上に向かって更新していく操作になっている。
計算量は、$i$に対してシフト演算を行うときと等しいことは明らかなので、$O(logN)$となる。

:::note warn
シフト演算
ある数 $x$ を右または左に1bitずらす操作のこと。
たとえば7(2進数で111)を右にシフトすると、3(011)となり、左にシフトすると14(1110)となる。
直感的には2で割ったり2を掛ける操作だと思っておけばよい。
:::

## どうやって実装するの

残念ながら、セグメント木はSTLで提供されるデータ構造ではない。
なので、自分で1から実装を行う必要がある。

```cpp:segment_tree.cpp
static const int max_n = 1 << 15; //数列a_iの最大の要素数を設定する
int seg_tree[2 * max_n];
int n;

//初期化を行う関数
void init(int n_) {
	//完全二分木にするため、データ数を2の倍数にする。
	n = 1;
	while (n < n_) n *= 2;

	//RMQを考えたいので、セグ木の各値はINT_MAXに設定しておく
	rep(i, 2 * n)seg_tree[i] = INT_MAX;
}

//index番目の値をxに変更する関数
void update(int index, int x) {
	index += n - 1; //最も下のレイヤーにおいて、1番目の値はseg_treeの中ではn番目だから
	seg_tree[index] = x;
	while (index > 0) {
		index = (index - 1) / 2; //親のノードのindex
		seg_tree[index] = min(seg_tree[2 * index + 1], seg_tree[2 * index + 2]);
	}
}

//区間[a,b)における最小値を求める関数
//indexはseg_treeにおける番号で、left,rightはseg_tree[index]の区間に対応
//query(a,b,0,0,n)として呼ぶことを考える。
int query(int a, int b, int index, int left, int right) {
	//考えようとしている区間が、[a,b)に全く含まれないなら、INT_MAXを返して、操作に影響しないようにする。
	if (a >= right || b <= left) return INT_MAX;

	//考えようとしている区間が[a,b)に完全に含まれているなら、その値を返せばよい。
	if (a <= left && b >= right) return seg_tree[index];

	//どちらでもない場合、seg_tree[index]の2つの子ノードに対して再帰的に操作を行う。
	int value_1 = query(a, b, 2 * index + 1, left, (left + right) / 2);
	int value_2 = query(a, b, 2 * index + 2, (left + right) / 2, right);
	return min(value_1, value_2);
}
```
【Next.js】Linkのaタグのスタイルを無効化


難しくありませんが、ググる手間を省くために

```react
<Link href="/">
  <a className="no-underline">
    <div>下線が消えるよ</div>
  </a>
</Link>
```

色も変えたくないときは

```react
<Link href="/">
  <a className="text-inherit no-underline">
    <div>aタグのスタイルを消すよ</div>
  </a>
</Link>
```
androidアプリ インターバルタイマーの開発

# CoCoIntervalTimer紹介ページ
筋トレなどの時に使用できるインターバルタイマーアプリの紹介です。

## 概要
たとえば、第1種目30秒、第2種目50秒、休憩20秒 以上の流れを×3セット!などの
プランを作成し、タイマーとして動作させます。


## 用語解説
-プラン
第1種目30秒、第2種目50秒、休憩20秒 以上の流れを×3セット!などのトレーニングメニュー全体を1つのプランとします。

-ステップ
プランを構成する要素です。
第1種目30秒→第1ステップ 第2種目50秒→第2ステップ

-シンプルプラン
ワーク部分と休憩部分を何セット行うかのシンプルなプランです。（30秒運動、10秒休憩を3セットなど）
シンプルプランはワーク秒数、休憩秒数、セット数を指定することで作成できます。

-カスタムプラン
複数ステップをカスタムしてプランを作成できます。
カスタムプランでは自由にステップを追加してより自由なプランを作成できます。
第1種目30秒、第2種目50秒、休憩20秒 以上の流れを×3セット!などはカスタムプランです。


## メイン画面
アプリ起動時に起動します。
作成済みのプラン一覧を表示します。
＋ボタンでプランの作成画面へ遷移します。
一覧表示されているプランをタップするとワーク画面へ遷移します。
リストの右側のボタンから作成済みのプランの編集、削除を行うことができます。
<img width="250" alt="メイン画面.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663059/9e7be7cf-9683-b70b-d198-033b6cc44d0a.jpeg">


## ワーク画面
メイン画面からワークを行うプランを選択することで遷移します。
選択されたプランの内容でタイマーを動作させます。
<img width="250" alt="ワーク画面.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663059/0bc6f613-10b0-4810-6551-70a52c164e4b.jpeg">

## プラン作成画面
シンプルプラン、カスタムプランの作成を行います。
メイン画面から＋ボタンで新規作成の画面へ遷移します。
メイン画面のプランリスト右側ボタンの編集から編集画面へ遷移します。
<img width="250" alt="プラン作成.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663059/ed9bd5ed-b86b-dac8-6f4c-4d132d6bcc27.jpeg">


## プライバシーポリシー
このアプリでは
ユーザーの個人情報を収集しません。
データを使用端末以外へ送信する通信機能はありません。
課金機能はありません。


## 最後に
本記事では、アプリを紹介するだけの記事になっています。
今後、本アプリや他アプリでの実装部分などの技術的な内容で記事を投稿していきたいです。
Ruby | Qiita API で記事を更新する ( PATCHリクエスト )



```rb


require 'net/https'
require 'uri'
require 'json'

uri = URI.parse("https://qiita.com/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true


QIITA_API_TOKEN = 'xxxxxxxxxxxxxxxxxx'

# https://qiita.com/YumaInaura/items/yyyyyyyyyyyyyyyyyyy のような記事URLから id が分かる
qiita_item_id = 'yyyyyyyyyyyyyyyyyyy'

patch_url = "https://qiita.com/api/v2/items/#{qiita_item_id}"
patch_request_header = {
 'Content-Type' =>'application/json',
 "Authorization" => "Bearer #{QIITA_API_TOKEN}"
 }
patch_request = Net::HTTP::Patch.new(patch_url, patch_request_header)

# タイトルと記事本文は必須
patch_request.body = {
 'title' => 'Title',
 'body' => "AAA\nBBB\nUpdated at #{Time.now}"
 }.to_json

patch_response = http.request(patch_request)

puts patch_response.body

```

# 更新の例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/ccca355b-2d98-993e-b9f9-79bf80c8d75e.png)










<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
JavaScriptでシンプルなオブジェクトを作成する

# オブジェクトはプロパティやメソッドから構成されている。
プロパティとは、オブジェクトの状態や特性を表すための情報のことであり、メソッドはオブジェクトを操作するためのものである。

```javaScript:sample.js
'use strict';
let sampleObject = {
  numarr:[1,2,3],
  name: 'Hanako',
  greet:function(){
    console.log(`Hello,${this.name}`);
  }
}

console.log(sampleObject.numarr);
sampleObject.greet();
```

結果:[ 1, 2, 3 ]
Hello,Hanako
SC-300メモ



# 勉強したこと

セルフサービスパスワードリセット
・ハイブリッド環境で有効にするにはライセンスがプレミアムであること
（365ではビジネスプレミアムとエンタープライズに含まれる）
Azure AD 外部コラボレーション

カスタムドメインの所有権の確認のためのDNS設定追加
・TXTレコードとMXレコードをDNSレジストラで登録する。

MFA認証方法
・モバイルアプリ認証コード
・電話へのテキストメッセージ（6桁のPIN）
・自動音声通話メッセージをユーザの電話に掛ける

ID保護、特権ID管理
･Azure AD premium2ライセンスが必要、E3以上

緊急アクセス用管理者アカウント
https://docs.microsoft.com/ja-jp/azure/active-directory/roles/security-emergency-access
・オンプレから同期されていないクラウド専用アカウント
・認証方法は他と異なるようにする
・グローバル管理者ロールを割り当て、サインイン ログと監査ログを監視し、定期的に検証する
パスワードハッシュ同期
・オンプレADが使えないときでも認証可能
パススルー認証
・オンプレにエージェントインストールが必要
ADフェデレーションサービス
・オンプレADに認証、スマートカード認証をサポート


パスワードレスソリューション
・Windows HELLO for Business　…　認証情報はローカル。生体認証・PINのため専用端末がいる
・FIDO　…　外部セキュリティキー・デバイスに組み込まれたプラットホームキー、専用端末いらない

# よくわかんなかったメモ

クライアントシークレット（アプリケーションパスワード）
・有効期限は最大24か月。
自己署名証明書
https://docs.microsoft.com/ja-jp/azure/active-directory/develop/howto-create-self-signed-certificate

Microsoft Defender for Cloud Apps(旧MCAS)
･ログ欠落のアラートは48時間後




サードパーティのセキュリティ情報およびイベント管理システムにエクスポートする
https://docs.microsoft.com/ja-jp/learn/modules/monitor-maintain-azure-active-directory/5-export-logs-to-third-party-security-information
・AzLogコマンドの使用　…　splunc、IBM QRadar､ArcSight


ゲスト ユーザー向けの SAML/WS-Fed ID プロバイダーとのフェデレーション
https://docs.microsoft.com/ja-jp/azure/active-directory/external-identities/direct-federation

Azure Active Directory の動的グループ メンバーシップ ルール
https://docs.microsoft.com/ja-jp/azure/active-directory/enterprise-users/groups-dynamic-membership
・等しくない　…　-ne
・等しい	…　-eq

Azure AD エンタイトルメント管理でリソースのカタログを作成して管理する
https://docs.microsoft.com/ja-jp/azure/active-directory/governance/entitlement-management-catalog-create
・Microsoft Graphのため委任された 「EntitlementManagement.ReadWrite.All」アクセス許可

# 試験対策

〇既存の環境等で注意すること
・グローバル管理者が割り当てられているクラウド専用のアカウントがあるか
僕なりに簡単にOpenAPIとSwaggerについてまとめておいた

<!-- wp:heading -->
<h2>はじめに</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>前の会社で他のチームがSwaggerを使用してAPI設計をしっかりと行なっているのを横目で見ていた。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>が、遂に自分もSwaggerとかOpenAPIとなるものに触れる機会がきた。<br>この機会にしっかりと習得してしまおうと思っている。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>そもそも、OpenAPIとかSwaggerってなんなのかわかっていなかったので、自分なりに調べて解釈した内容をここにまとめておこうと思う。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>超ざっくり書きますが、おかしな点がありましたらご指摘お願いします。</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>OpenAPIとSwagger</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3>OpenAPI</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p><span class="marker-under">OpenAPIというものは、<code>フォーマット</code>のことを意味する</span>らしい。このフォーマットを使用すると、機会が読めるAPIの仕様を記述することができる。このフォーマットは、XMLもしくはYAMLで記述をする。YAMLで記述されているのが一般的というか、多いっぽい。</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Swagger</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>では、Swaggerとはなんなのか。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><span class="marker-under">Swaggerは、<code>OpenAPIを作成したり、表示したり、利用したりするためのツール群</code>のことを意味する</span>らしい。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code>ツール群</code>になるので、いくつかツールが存在する。</p>
<!-- /wp:paragraph -->

<!-- wp:table -->
<figure class="wp-block-table"><table><thead><tr><th>ツール名</th><th>概要</th></tr></thead><tbody><tr><td>Swagger Editor</td><td>OpenAPIを記述するためのエディターのこと</td></tr><tr><td>Swagger Codegen</td><td>Swagger Editorで生成されたOpenAPIを読み取ってソースコードを生成してくれたりする</td></tr><tr><td>Swagger UI</td><td>OpenAPIを読み取り、仕様書として表示してくれる</td></tr></tbody></table></figure>
<!-- /wp:table -->

<!-- wp:paragraph -->
<p>こういうものがあるらしい。</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>おわり</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>ちょっととっかかりは難しそうに感じるが、調べてみるとなんとなくわかる。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>実際にOpenAPIを書いてみると、なんとなくできたし、がんばろう。</p>
<!-- /wp:paragraph -->
ClickUpのイベントをLambdaで取得してみた

## はじめに
業務でClickUpを使用していますが、タスクのコメントが追加された際にSlackに通知できるようにしたいと思いました。
まずは、Lambdaでイベントを受け取る方法についてまとめました。

## 準備
### Lambda
- 関数を作成する
- 今回は簡易性のためにAPI Gatewayは使わずに関数URLを使う

### ClickUp

- 以下に記載の順序でAccessトークンを取得する

> Finding your token: 
> Navigate to your personal Settings 
> Click Apps  in the left sidebar
> Click Generate  to create your API token
> Click Copy  to copy the key to your clipboard 

https://docs.clickup.com/en/articles/1367130-getting-started-with-the-clickup-api


- 以下コマンドでWebhookを作成する
```bash
curl --include \
     --request POST \
     --header "Authorization: "access_token"" \
     --header "Content-Type: application/json" \
     --data-binary "{
    \"endpoint\": \"https://yourdomain.com/webhook\",
    \"events\": [
        \"taskCreated\",
        \"taskCommentPosted\",
        \"taskCommentUpdated\"
    ]
}" \
'https://api.clickup.com/api/v2/team/{team_id}/webhook'
```
- 補足
    - access_token: 上記で取得したアクセストークン
    - endpoint: イベントを通知したいURL。今回はLambdaの関数URLを指定
    - events: 連携したいイベントを列挙する。指定方法は公式ドキュメント参照。今回は以下イベントを取得
        - taskCreated: タスクが作成された時のイベント
        - taskCommentPosted: タスク内でコメントが投稿された時のイベント
        - taskCommentUpdated: タスク内のコメントが更新された時のイベント
    - team_id: ワークスペースのID

## 検証

それぞれのイベントに関して検証した。
レスポンスの内容は以下公式ドキュメントに例が記載あるので、ここでは記載しない。
- https://clickup.com/api

### taskCreated

- 問題なく連携されることを確認できた。

### taskCommentPosted

- スレッドでない場合は、問題なく連携されることを確認できた。
- スレッド内でコメントを投稿した場合は連携されなかった。

### taskCommentUpdated

- スレッドでない場合は、問題なく更新されることを確認できた。
- スレッド内のコメントを投稿した場合は連携されなかった。

## まとめ
- ClickUpのイベントをLambdaで受け取ることができた。
- しかし、スレッド内のコメントが通知されないのがイマイチだと感じた。
    - 以下で書いてる人がいますが、今後対応されると嬉しいです。
       	- https://clickup.canny.io/feature-requests/p/threaded-comments-cant-trigger-webhook

## 参考
- https://clickup.com/api
cannot load such file -- sasscエラーについて

本日も頑張っていきましょう。宜しくお願いします。

こんなエラーが出ました。
![スクリーンショット 2022-05-14 11.35.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607524/919f091c-899c-dc75-4afe-b8192e41f5bc.png)

どうやらこれはRails7以降で起きるエラーのようです。
従来通りにCSSを呼び出すとこのエラーが発生するようです。

以下対応をすると解決できるようなので試してみます。

```gemfile.qiita.rb
# gem "sassc-rails"
```

この、コメントアウト（＃）を削除して、ターミナル上で
「bundle install」を実行してみます。

無事、エラーが解消されました！
既存の IAM ロールが削除されると、該当ロール名がプリンシパル ID に変換される

ある日突然 Terraform 差分が起きた件について、調査して分かったことをメモ

Assume Role 設定で指定していた IAM ロールの ARN が、見覚えのない文字列（`AROA`から始まる）に変更されていて、Terraform 適用時に差分が起きた

```tf
Principal = {
  ~ AWS = "AROA..." -> "arn:aws:iam::[アカウント ID]:[ロール名]"
}
```

この変更を行った覚えはなくて、調査した結果、該当 IAM ロールが削除されたことによって、ARN からプリンシパルID に変換されたことが原因だった

どういうことかと言うと、
- 前提として、AWS の仕様で、意図しない IAM ロール利用を防ぐために、IAM ロールは裏側でユニーク ID で管理されている
- [普段は AWS 側で必要な時に ID 変換されるため目にする機会がないが、arn が指す IAM ロールが削除されると、この ID がコンソール表示される](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html#:~:text=%E3%83%AD%E3%83%BC%E3%83%AB%E4%BF%A1%E9%A0%BC%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E3%81%AE%20Principal%20%E8%A6%81%E7%B4%A0%E3%81%AB%E3%80%81%E7%89%B9%E5%AE%9A,%E6%96%B0%E3%81%97%E3%81%84%E3%83%97%E3%83%AA%E3%83%B3%E3%82%B7%E3%83%91%E3%83%AB%20ID%20%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82)
    - これによって、Terraform の差分が発生した

ちなみに、[削除されている（存在しない） IAM ロールは ARN 指定することはできず（設定時に AWS 側で存在チェックをしている）](https://qiita.com/Ichi0124/items/98a8cdc7c942a2e03cb9)、実際、AWS コンソール・Terraform から設定しようとしたができなかった
自作キーボード設計のすゝめ


いつものキーボード設計してから発注するまでの流れをメモがてら書いておく．


## １．キーボードのレイアウトの作成

[keyboard layout editor](http://www.keyboard-layout-editor.com/#/) でレイアウトを作成．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294169/41256af0-10cf-710b-6f04-4980f1d24b23.png)

ブラウザでできるので手軽にあれこれ試せます．
再読み込みをすると編集した結果が全部消えるので注意．
完成したら右上の`Download`からjsonファイルをダウンロードしておきましょう．
後で再編集したくなったときにjsonファイルを読み込ませることができます．
また，Sign inしておくとセーブすることができるのでそちらでもいいかもしれません．


## ２．プレートの作成

keyboard layout editor の`</>Raw data`の内容をコピーしておく．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294169/b931e61a-d2c0-9b5f-8ace-10613c742177.png)

[AI03 PLATE GENERATOR](https://kbplate.ai03.com/) or [Plate & Case Builder](http://builder.swillkb.com/)でプレートを作成．

### AI03 PLATE GENERATOR
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294169/e7cf3cea-1db4-4e9a-dc1e-2b28df8e3f83.png)


1. **KLE RAW DATA**にkeyboard layout editorから`</>Raw data`をコピペ．
2. あとはデフォルトで良さそう
3. `DOWNLOAD DXF`

### Plate & Case Builder

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294169/8852cc67-ec78-87e4-098d-599dc24867a2.png)

1. **Plate Layout** : keyboard layout editor から </>Raw data をコピペ．
2. **Switch Type**: Mx{_t:1}
3. **Stabilizer Type**: Cherry Only {_s:2}
4. Click `Draw My Cad!!!`
5. Click `DXF`


## 3.fusion 360でケースを設計．

`挿入`＞`DXFを挿入`から先ほど作成したDXFファイルを挿入する．
プレートの外形を整える．

## 4.kicadで基板設計．

回路を設計し，PCBエディターで`3.`で作成したプレートデータを読み込みフットプリントを配置する．
プラグインの[keyboard-layouter](https://github.com/yskoht/keyboard-layouter)を使うとkeyboard layout editorで作成したレイアウトどおりに自動配置してくれるのでおすすめ．
筆者も[自分用にカスタム](https://github.com/mizuho1998/keyboard-layouter)して使っている．

## 5. その他

基板の発注，必要パーツの購入，組み立てなどなど色々して完成．


## 参考
https://www.youtube.com/watch?v=iqwvNML2toI&list=WL
Udemy、ウェビナー等の動画閲覧で活用しているツール

Udemyやウェビナー等の動画プレーヤーの標準機能では物足りないことがあります。
今回は、普段活用しているツールを2点紹介します。

# [Video Speed Controller](https://github.com/igrigorik/videospeed)
再生速度を好みに応じて調整することができます。
Edge,Chromeの拡張機能に対応しています。

Udemy等の大抵のサイトは、標準実装されており本ツールは不要ですが、一部ウェビナー(アーカイブ配信)ではそこまでの機能を持っておらず、そういったときに便利です。
ショートカットキーを設定しておけば、一発で指定の速度に設定することができます。
私は1.5～2倍の速度で設定することが多いです。

# [eJOY English](https://ejoy-english.com/extension)
リアルタイムで音声を字幕化＆自動翻訳を行うことができます。
Chromeの拡張機能に対応しています。

複数言語を同時に字幕化できますので、例えば、英語と日本語の両方を表示することも可能です。日本語訳がおかしい時もありますが、そういったときは英語字幕で補完しながら見ます。
また、英文/英単語を選択し本ツールを起動するだけで、翻訳・発音を行う機能があります。
Udemy、Courseraの日本語に対応していないコースではフル活用しています。

以上、ツールを紹介させて頂きました。
M5StackでVSCodeを使ったMicroPythonをやろうとしたけど「Cannot read properties of undefined (reading 'sendCommand')」のエラーが出た

## 結論から言えば

[![Image from Gyazo](https://i.gyazo.com/47fa54db57547cda1c7ae56e69c78907.png)](https://gyazo.com/47fa54db57547cda1c7ae56e69c78907)

VSCode中のエクスプローラーではなく、その下のM5STACK DEVICEの中のファイルを開いて（編集して）から実行ボタンを押すこと

## 公式のQuickStartに漏れてる気がする

https://docs.m5stack.com/en/quick_start/m5core/mpy

最後あたりに書いてもらえたらよかった…

ちなみに今回はM5Stackだったが、Core2も書いてなかったし、同じようなエラーが出ていたので同じことだと思う

## 拡張機能の中に書いてあって気づいた

[![Image from Gyazo](https://i.gyazo.com/1bf5e6fc0999c7551e39cf2fb092126c.png)](https://gyazo.com/1bf5e6fc0999c7551e39cf2fb092126c)

ここに書いてあった〜

## ざっくり手順メモ

詰まったところ以外公式のとおりなのでざっくりいきます

* ドライバ2種類インストール
    * （Macだと入れなくてもできた…かも）
* M5Burnのインストール
* M5BurnでM5StackにUIFlowの書き込み
* VSCodeインストール
* VSCodeの拡張機能の「vscode-m5stack-mpy」のインストール
* M5Stackの設定でUSBモードにする
* VSCodeでデバイスの選択
* 【NEW】VSCode上で「M5STACK DEVICE」の中からファイルを選択
    * test.pyとかがいいのかな
* VSCodeで右上の実行ボタンを押す
exploit kit とは

## 勉強前イメージ

rootkit調べてたときに出てたから似たような感じ？

## 調査

### exploit kit とは

エクスプロイトキット と読み、システムの脆弱性を攻撃するプログラムをパッケージ化したハッキングツールになります。

元々エクスプロイトとは、システムの脆弱性を攻撃するプログラムのことを指し
webブラウザの脆弱性を狙ったり、ブラウザからアクセスできるプログラムのセキュリティホールを悪用したりします。
そのプログラムをパッケージ化したものがエクスプロイトキットと言われています。

最近ではSaaSをもじったEaaS(Exploit Pack as a Service)と言われるプラットフォームを通じて
エクスプロイトキットのホスティングサービスも存在すると言われています。

### exploit kitの感染経路

- リンクをクリックさせる

ユーザにリンクをクリックさせてwebページを開く。
スパムメールなどが感染経路になる。

- 接続させる

攻撃元のサイトに接続される。
主にクロスサイトスクリプティングなどが利用される

- セキュリティホールを確認

ユーザのPC・デバイスの脆弱性を確認する
エクスプロイトキットはよく利用されているアプリケーションを狙って修正パッチが当てられていない脆弱性を利用しています。

- ウイルスを仕込む

ユーザのPC・デバイスに合うツールを選んでいウイルスを仕込む

### rootkitとの違い

よく似たようなもので [rootkit](https://qiita.com/miyuki_samitani/items/7e180e5d2b81adfdaa84) が言われますが、
その違いは以下になります。

- rootkit : 攻撃者が侵入した後、気づかれないように遠隔操作するツール
- exploit kit : 攻撃者が侵入する前、攻撃するプログラムをパッケージ化したツール

exploit kit は主に侵入前に使用され、rootkitは侵入後に利用されます。

## 勉強後イメージ

攻撃する方もいろいろパッケージ化して効率的にしようりとしてるのね。。。

## 参考

- [エクスプロイトキットとは](https://www.trendmicro.com/vinfo/jp/threat-encyclopedia/web-attack/202/exploit-kit)
- [エクスプロイトキット 【exploit kit】](https://e-words.jp/w/%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%97%E3%83%AD%E3%82%A4%E3%83%88%E3%82%AD%E3%83%83%E3%83%88.html)
開発勉強（controller)

今回も頑張っていきましょう。

今日は、前回なんとかサーバーの立ち上げまでできたので、実際に開発に向けて勉強していきます。

⭐️ MVC
　　・Railsは「MVC」というアーキテクチャーを使ったフレームワーク
　　・MVCというのは、「Model」「View」「Controller」の略
　　・この３つの中で最も重要なのは「Controller」
　　
⭐️ コントローラーを作成する
　 ターミナル上で前回作成したRailsAppへ移動し、以下コマンドを実行する
```ruby:qiita.rb
rails g controller 名前
```
　　※名前は半角英字とすること
```ruby:qiita.rb
      create  app/controllers/hello_controller.rb
      invoke  erb
      create    app/views/hello
      invoke  test_unit
      create    test/controllers/hello_controller_test.rb
      invoke  helper
      create    app/helpers/hello_helper.rb
      invoke    test_unit
```
　　これで作成ができました
ラズパイでPythonのvenvを使いつつCronで定期的に自動実行する方法

# Pythonスクリプトをvenv環境下で起動する、Crontab設定を記述してみた。
Windows上で開発していたプログラムをRaspberryPiに移植したときに、日々手動で実行するのもめんどくさいし、実行するのを忘れたりすることも多々あったので、自動化するべと意気込んでやってみた。

# 実際に行った作業
まずはcrontab -e を実行。
![crontab.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271862/0639948f-e198-5699-d2ec-622a8760d009.jpeg)
cron上で、まずカレントディレクトリを移動して、仮想環境の.venv/binにあるpythonでpyファイルを起動するという感じ。
![crontab2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271862/bdeaf98b-6b58-cba5-e242-8bb45c6f9451.jpeg)


※**参考にしたのは以下の記事**
[cronの書式で曜日指定に数字を使うのやめたい](https://qiita.com/skokado/items/ef82a197350c4322a53f)
[venv環境でpythonスクリプトをcronで周期実行](https://qiita.com/gao_gao/items/12a1e9620bddbff7463f)
WIP: Oracle JDK は Java 17 以降も本番環境では有償の可能性あり

:::note alert
**この記事は、誤った内容を含む可能性があります。** 
2022/05/14 時点での筆者個人の見解に基づいて記載されており、筆者の所属組織の見解や、筆者自身が Oracle 社に直接確認した情報を表すものではありません。

この記事は、確定的な情報を提供することはできませんが、そもそも懸念があることにすら気付けていない人への注意喚起になればと思って公開します。願わくば、今後誤解が起きづらい状態に何かしらのアップデートがあることを期待します。
:::

Java 17 のリリースとともにアナウンスされた Oracle JDK の [NFTC (Oracle No-Fee Terms and Conditions) ライセンス](https://www.oracle.com/downloads/licenses/no-fee-license.html) により、乱立する JDK ディストリビューション問題に決着をつけ、今後は Oracle JDK でいけると思った人も多いのではないでしょうか。

Webでもこのライセンス変更が大きく取り上げられたことは、記憶に新しいと思います。

* [Introducing the Free Java License](https://blogs.oracle.com/cloud-infrastructure/post/introducing-free-java-license)
* [Oracle JDK 17 - 再び商用利用が無料に](https://www.infoq.com/jp/news/2021/11/oracle-jdk-free-again/)
* [オラクル、Oracle JDKを再び無料提供へ、本番環境でも利用可。昨日リリースのJava 17から － Publickey](https://www.publickey1.jp/blog/21/oracle_jdkjava_17.html)

かくいう私もその一人だったのですが、Java 17 への移行を検討していた矢先、（自分が当時刷り込まれていた理解に反して）Oracle JDK は今後も SaaS などの対外的な商用サービスでは有償になるという情報を見つけました。

実際の本番利用にあたっては、自身のプロダクトでの利用形態に照らし合わせ、ライセンス条文の確認や、法務への相談などを実施して判断することを強くオススメします。

### 前提

* Oracle JDK 17 以降
* Web ブラウザ経由の商用サービス（Web サービス）
* サーバー側で Java を実行

### 結論

* SaaS のように外部にサービス提供する Web アプリケーションにおいて、NFTC ライセンスで Oracle JDK 17 以降を無償で本番利用することはできない

### 経緯

発端。`personal use` と `internal business operations` に限定されており、 `internal business operations` には SaaS のような外部へのサービス提供を含まないのでは？という問題提起

https://twitter.com/nagise/status/1506414770244624384

伊藤さんが Oracle 社内で確認したところ、 `internal business operations` には外部へのサービス提供を含まない、すなわち **外部向けアプリケーションでは本番環境は有償利用になる** との回答

https://twitter.com/itakash/status/1506560369569202176

https://twitter.com/itakash/status/1506564024640876545

元のブログ記事からもFAQからも読み取りづらいよね、という声。最終的にはライセンス条文を読んで、でしかないのはその通りなのだと思いますが、このへんの情報がベースに各種の Web 記事が作られて誤解が拡散している気がするので、全く同感です。

https://twitter.com/yusuke/status/1506566669392826371

### 参考情報

* [Oracle No-Fee Terms and Conditions (NFTC) License Agreement](https://www.oracle.com/downloads/licenses/no-fee-license.html)
* [Oracle JDK License General FAQs](https://www.oracle.com/java/technologies/javase/jdk-faqs.html)
* [Introducing the Free Java License](https://blogs.oracle.com/cloud-infrastructure/post/introducing-free-java-license)
* [Oracle JDKのNFTCライセンスに関する注意点まとめ](https://togetter.com/li/1862736)
AWS公式資料で挑むMLS認定(7)-Amazon Pollyの基本

##### [前回] [AWS公式資料で挑むMLS認定(6)-Amazon AIサービスの全体像](https://qiita.com/mingchun_zhao/items/35a4555225e66b957d1a)

## はじめに

今回は、Amazon AIサービス勉強の第1弾、Amazon Pollyです。

## Amazon Pollyとは

- 文章をリアルな音声に変換する、テキスト読み上げ(TTS)サービス
    - TTS(Text-To-Speech)とは、テキスト(文章)を入力し、望む言語の音声を生成する、テキスト音声合成
    - テキスト読み上げ機能により、新しいタイプの音声対応製品を構築できる
- 深層学習(ディープラーニング)技術を使用し、自然に聞こえるように人間の音声を合成
    - 何十種類のリアルな音声を多数の言語でサポート
    - [サンプル音声](
https://aws.amazon.com/jp/polly/)の発音はネイティブレベルでした(日本語、英語、中国標準語、韓国語のみ聞いてみた感想)
- 標準TTS音声に加え、ニューラルテキスト読み上げ(NTTS)音声を提供
    - NTTSは、新しい機械学習アプローチにより、音声品質の高度改善を実現
    - ニュースナレーションでニュースキャスターの発話スタイルもサポート(すごい)
- Amazon Pollyブランド音声で、組織のカスタム音声を作成
    - Amazon Pollyチームと連携し、組織専用のNTTS音声を作成

## Amazon Pollyのメリット

- 自然な声
    - 数十種類言語と自然な男女の音声を豊富に備えている
    - 流暢なテキスト読み上げで、高品質の音声出力を提供
- 音声保存と再配信
    - 生成した音声を追加料金なしで無制限に再生可能
    - 音声ファイルはMP3、OGCなど標準フォーマットで生成
    - クラウドまたはローカルで、アプリやデバイスにてオフライン再生可能
- リアルタイムストリーミング
    - リアルな声と会話型ユーザーエクスペリエンス配信で、一貫した速いレスポンスタイムを提供
    - Amazon Polly APIに文章を送ると、音声がストリームとして返され、直ちに再生可能
- 音声出力のカスタマイズとコントロール
    - 音声を修正し、ニーズに合わせられる
    - 辞書とSSMLタグをサポートし、発音/声量/声の高さ/速度など`音声の相`をコントロール可能
        - SSML(Speech Synthesis Markup Language)は、音声合成マークアップ言語
            - 合成音声の生成用にテキストをマークアップする
- 低コスト
    - 従量課金制
    - 文字単位変換による低コスト
    - 無制限再生

## Amazon Pollyのユースケース

- コンテンツの作成
    - 数十種類言語で音声を生成でき、RSSフィード/ウェブサイト/動画などの視聴者向けに音声を届ける
    - アーキテクチャ例: 記事を音声に変換し、MP3でダウンロードする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/e28cba4a-8a5f-d46e-bc96-69b782ea1e29.png)

- eラーニング
    - 音声と同期した下記ビジュアル機能を開発可能
        - 顔のアニメーション
        - カラオケで単語のハイライト
    - 文/単語/音の発音関連情報を含むメタデータストリームをリクエスト可能
        - メタデータストリームをオーディオストリームとともに下記合成音声に使用
            - アプリ内でアバターをアニメーション化
            - 発音中のテキストを`ハイライト`(ハイライトまでできる?面白い)
    - アーキテクチャ例: 音声再生および発音対象テキストハイライト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/f9be29ec-21ef-d5a0-18da-bd00387b377c.png)
- テレフォニー
    - コンタクトセンターで自然な声で応答可能
    - 音声出力をキャッシュ/再生することで、Amazon ConnectなどIVRシステムで音声自動応答可能
        - IVR(Interactive Voice Response)とは、コンピューターによる音声自動応答システム
    - Amazon Polly APIを活用し、下記情報をリアルタイムに自動配信可能
        - サービスステータス
        - アカウントや請求書に関する問い合わせ
        - 住所、連絡先情報
    - アーキテクチャ例: 電話システムでテキスト読み上げ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/6eeda0cd-763c-ba39-a9ab-b755d0c1ed3b.png)

※ 引用元: [Amazon Polly ユースケース](https://aws.amazon.com/jp/polly/)

## おわりに

Amazon Pollyの機能概要とユースケースを勉強しました。
次回は、技術の側面からAmazon Pollyを深掘りします。
お楽しみに。

##### [次回] [AWS公式資料で挑むMLS認定(8)-Amazon Polly音声変換の仕組み](https://qiita.com/mingchun_zhao/items/5204ddf6445e55ecc010)
firebase認証でログインできるユーザを一部のドメインに制限する

google firebase認証のログインプロバイダをgoogleにすると、すべてのgoogleユーザがログインできてしまう。自社ユーザ限定したい場合は、「Firestore Database」メニューの「ルール」タブでisValidUser関数をカスタマイズすることで、簡単に実現できる


```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if isValidUser();
    }
  }

  function isValidUser() {
    return request.auth.uid != null && (
      request.auth.token.email.matches('.*@mydomain1.com')
      || request.auth.token.email.matches('.*@mydomain2.com')
    );
  }
}
```
herokuでsecret_keyを使う

## はじめに
アプリをherokuにデプロイし、ログイン機能を使用しようとしたところ、このようなエラーが出ました

    JWT::DecodeError (No verification key available)

この解決方法を共有いたします。

## 結論
herokuにマスターキーを登録するのを忘れてたので、追加しました。

    heroku config:set RAILS_MASTER_KEY=`cat config/master.key`

### 発生状況
ログイン認証でJWTを使って、デコードする際に、`Rails.application.credentials.secret_key_base`を使っています。
この値がnilとなっており、エラーが発生しておりました。

    def decode(token)
      JWT.decode token, Rails.application.credentials.secret_key_base
    end

そもそもこれは、credentials.yml(公開鍵)の値をmaster.key(秘密鍵）を使って取得しているようです。
ですので、herokuにもマスターキーを登録する必要がありました。