OmniAICreator/Qiita-1.07M huggingface dataset:
HTTPのPUTとPATCH違い

HTTPメソッド中、PUTとPATCHはリソースをUPDATEするとき使用する。同じ機能だと勘違いしやすい2つのリクエストには若干の違いがある。
[Mapping Annotationの@PatchMapping](https://qiita.com/KyungJoon960/items/942e591b75eb87d68598)で簡単に書いたことがあるがもう一回整理してみる。
PUT：リソースのすべてを更新する。
PATCH：リソースの一部を更新する。    

---
下のようなリソースがあるとする。
| id | name | address | gender |
|:-:|:-:|:-:|:-:|
| 1 | Kim  | Seoul | M |
| 2 | Mari | Tokyo | F |
| 3 | Luis | Madrid | M |
---

- **PUT**
（1）リソースのすべての項目にUpdateリクエスト

``` 
PUT /id/1

{
    name : "Jane",

    address : "NY",

    gender : "F"
}
```
結果：id1のデータがすべてUpdateされる。

| id | name | address | gender |
|:-:|:-:|:-:|:-:|
| 1 | Jane  | NY | F |
| 2 | Mari | Tokyo | F |
| 3 | Luis | Madrid | M |

　<tr>

（2）リソースの一部の項目にUpdateリクエスト

```
PUT /id/1

{
    address : "LA"

}
```
**結果：リクエストしてない項目もUpdateされるため、id1のnameとgenderはNullになる。**

| id | name | address | gender |
|:-:|:-:|:-:|:-:|
| 1 |  | LA |  |
| 2 | Mari | Tokyo | F |
| 3 | Luis | Madrid | M |

　<tr>

（3）リクエストしたリソースがない時
```
PUT /id/4

{
    name : "Victoria",

    address : "London",

    gender : "F"
}
```
結果：以下のように新しいリソースが追加される。

| id | name | address | gender |
|:-:|:-:|:-:|:-:|
| 1 | Kim  | Seoul | M |
| 2 | Mari | Tokyo | F |
| 3 | Luis | Madrid | M |
| 4 | Victoria | London | F |

　<tr>

---

- **PATCH**
（1）リソースのすべての項目にUpdateリクエスト

``` 
PATCH /id/1

{
    name : "Jane",

    address : "NY",

    gender : "F"
}
```
結果：PUTと同じくid1のデータがすべてUpdateされる。

| id | name | address | gender |
|:-:|:-:|:-:|:-:|
| 1 | Jane  | NY | F |
| 2 | Mari | Tokyo | F |
| 3 | Luis | Madrid | M |

　<tr>

（2）リソースの一部の項目にUpdateリクエスト

```
PATCH /id/1

{
    address : "LA"

}
```
**結果：リクエストした項目のみUpdateされるため、id1のnameとgenderは元のデータを維持する。**

| id | name | address | gender |
|:-:|:-:|:-:|:-:|
| 1 | Kim  | LA | M |
| 2 | Mari | Tokyo | F |
| 3 | Luis | Madrid | M |

　<tr>

（3）リクエストしたリソースがない時
```
PUT /id/4

{
    name : "Victoria",

    address : "London",

    gender : "F"
}
```
結果：新しいリソースは追加されない上、ServerはClient ErrorをResponseとして返す。

| id | name | address | gender |
|:-:|:-:|:-:|:-:|
| 1 | Kim  | Seoul | M |
| 2 | Mari | Tokyo | F |
| 3 | Luis | Madrid | M |

　<tr>

---

#### まとめ
- PUT：リソースのすべてを更新するため、リクエストしなかった項目もNullとしてUpdateされる。
- PATCH：リソースの一部を更新するため、リクエストしなかった項目は元のデータを維持する。
【Rails】検索フォームをヘッダーに追加する

 # はじめに
検索フォーム(検索窓)を実装する。
**仕様**
・ヘッダーに検索フォームを追加し、テンプレートを崩さない。
・送信ボタンは実装しない。
・form_withを使用する。
・虫眼鏡マークと検索フォームが重ねる。
・検索キーワードが空白の時は、全ての投稿を返す。
・検索キーワードがタイトルと内容に一致するを記事を検索する。
![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/3bd31692-4117-5184-6247-85c94b2d6e58.gif)


# 環境
| No |    項目     |   内容    |
|---:|-------------|------------|
| 1  |      OS       |   Mac     |
| 2  |       Ruby      |   2.6.3   |
| 3  |       rails      |      6.0.4 |
4|sass-rails|5.1.0

# 実装
# routes.rbの設定をする
search_pathに対してPost、Getリクエストを設定する。
```routes.rb
    post '/search',  to: 'posts#search'
    get  '/search',  to: 'posts#search'
```

# postモデルを検索するsearchメソッドを実装する
後で設定するpostコントローラーで使用する検索用メソッドを実装する。
・検索キーワードが空白の時は、全ての投稿を返す。
・検索キーワードの前方後方で一致するタイトル、もしくは内容の記事を検索する。
```post.rb
  # Postテーブルのcontentカラムを検索する
  def self.search(search)
    return Post.all unless search
    Post.where(['content LIKE(?) OR title LIKE(?)', "%#{search}%", "%#{search}%"])
  end
end
```

# ヘッダーに検索フォームのView設定
ヘッダーに検索フォームを追加する。
送信ボタンは実装せず、inputフォームを選択した状態でEnterを押すと検索できる仕様にする。
iタグはfontawesomeから虫眼鏡マークを取得してきた。
```html:_header.html.erb
...    
<div class="search">
    <i class="fa-solid fa-magnifying-glass"></i>
    <%= form_with(url: search_path, scope: :post, local: true) do |f| %>
      <%= f.text_field :search, placeholder: "キーワード検索" %>
      <% f.submit %>
    <% end %>
</div>
...
```

# Postコントローラーにsearchアクションを設定する
検索結果で下記を表示するため、インスタンス変数を定義して、Viewに渡す。
@keyword: 検索したキーワードを表示 
@post_all: キーワードがヒットした記事の数
@posts: paginationする
```posts_controller.rb
  def search
    #Viewのformで取得したパラメータをモデルに渡す
    @keyword = params[:post][:search] if params[:post]
    @posts_all = Post.search(@keyword)
    @posts = Kaminari.paginate_array(@posts_all).page(params[:page]).per(10)
  end
```
`if params[:post]`によってnilガードをしている。
検索結果画面でリロードしたときはなにも送信されないので、params[:post]はnilとなり、nilに対して[:search]メソッドすると、エラーになる。

# 検索結果のViewを設定
検索結果を表示するページを記載する。
```html:posts/search.html.erb
  <div class="col-md-8">
    <h3>検索結果</h3>
    <p>
      検索キーワード: "<%= @keyword %>"  <br>
      一致した記事: <%= @posts_all.count  %>
    </p>
    <%= paginate @posts %>
    <ul class="posts">
      <% @posts.each do |post| %>
        <%= render 'posts/post', post: post %>
      <% end %>
    </ul>
    <%= paginate @posts %>    
  </div>
```
今回検索フォームと虫眼鏡マークを重ね合わせる仕様にしているため、sassの設定もする。
```custom.scss
.search {
  float: left;
  position: relative;
  i {
      color: gray;
      position: absolute;
      left: 10px;
      bottom: 5px;
    }
  input {
    border: 1px solid #bbb;
    border-radius: 12px;
    margin: 13px 5px;
    padding-left: 22px;
    margin-bottom: 0;
    width: 140px;
    outline: none;
    background-color: #bbb;
    &:hover {
      opacity: 0.8;
    }  
  }
}
```


# おわりに
これで、検索フォームを実装できた。
参考記事
[CSS「position:relative」と「position:absolute」で画像や文字を重ねる方法](https://naifix.com/relative-absolute/)
[railsで検索フォームを作ろう！！](https://qiita.com/yusuko/items/cff4e46aeafbc3beecf2)
[](https://qiita.com/tomato1125/items/a8dbaf344831357aaf3a)
SSHの使用を禁じられたColaboratoryへの想いは変わらず(Localで開発した.pyをColab上で楽実行できた報告)

# 前置き(急ぐ方はSKIP)

Google Colaboratory(以下、colabo)上でSSHの使用が禁じられてしまいました。
つまり、そのまま.pyでの実行が禁じられてしまったと判断します。
これからは、Colabo=Jupyterノートブックから開発コードを呼び出さねばならず、手間が増える事が懸念でした。

ColaboProを使用する前だったので、他の手段(別：HPC提供サービス)も検討しましたが、コスパではcolaboがよさそうです。
GPUマシンが壊れたり、買い替え先にNVidia-GPUが無い場合に、Colaboが使えるかどうか確認が必要でしたので、次の通り試しました。

# 結論 : RemoteDebug不可は痛いが、十分使える
1. 結論: LocalPCで開発した.pyは楽実行可。
1. **ただし、SSH無しはPyCharmやらから実行不可は不便**。
1. 予備策として。ただし、RTX2080より遅い？1,072円/月はコスパ良いかな。
1. 変更を要するかもしれない点
    1. Pyhon3.7互換コードへと修正
        1. 2022.8.19現在, ColaboのPyは3.7.13。
    1. [PoetryがColabo上で使えない](https://qiita.com/slave/items/172e5c6897dc4577e063)。
        1. 私は**requirements.txtへ切り替えた**。
        1. pipenvも使えないかも。
1. ソースコードの同期方法
    1. GitHub経由 : [Colab 上で GitHub を使用する](https://zenn.dev/smiyawaki0820/articles/e346ca8b522356)
    1. GoodSync, RealTimeSyncなどからLocalPC<->GoogleDrive(以下GDrive)経由。 ←こちらを説明します。
2. 生成物の保存(セッション切れ問題)
    2. GDriveへ保存されるのでセッション切れになっても、**出力ファイルは全てGDriveへ保存される**。

# 手順 : コード同期
1. 私はGoodSyncでLocalPCからGDriveへプロジェクトフォルダをコピーします。
    1. 代替手段
        1. [RealTimeSync](https://freefilesync.org/manual.php?topic=realtimesync)
        1. Googleの純正Client
1. 以下はGDriveの話
1. プロジェクト内でColaboノートブックを生成
1. 下記コードをセル内に記載して行く。

- 各変数の設定
**Colaboratory/JupyterNotebookでは`!`から開始して定義した変数をPython内でそのまま使える**事を利用して、冒頭にプロジェクトPATHなどを定義して、残りのコードが使い回せるようにします。

```
# GDrive上のProject FolderへのPATH
prj_path_on_gdrive = "/path/project/on/gdrive"

# requirements.txtへのPATH(ただし、Projects上)
req_txt_rpath="requirements4colabo.txt"

# 実行時のCWD
cwd_run="src"

# 実行する.py
main_py_rpath="main.py"

# 上記実行.pyへのパラメータ
param4py="
```


- GDriveのマウント
```
# mount Google Drive
from google.colab import drive
drive.mount('/content/gdrive'
```


- projectのCWD変更
```
myprj_abs_path="/content/gdrive/MyDrive"+prj_path_from_gdrive
%cd $myprj_abs_path
%ls
```


- シンボリックリンクを張る
```
#
# ProjectExplorerにプロジェクトDirへのシンボリックリンクを生成
import os
# 末尾のFolderNameを取り出し、そのフレーズを仮想フォルダ名としてシンボリックリンクを張る
last_dir=os.path.basename(os.path.normpath(myprj_abs_path))
print(last_dir)
!ln -s $myprj_abs_path /content/$last_dir
```


- 必要なパッケージをインスト
```
!pip install -U -r $req_txt_rpath
```

- main.pyを呼び出す
```
%cd $cwd_run
# [パラメータ] ※パラメータはargparse/clickを使って指定できるようにしておくのが良い。
if param4py=="":
    # パラ無し
    # param4py2=""
    !python $main_py_rpath
else:
    # パラ有り
    # param4py2="-m "+param4py
    !python $main_py_rpath param4py
```

以上。

poetryが使えない事でハマってしまった以外は、代替GPUとして有用そうです。
TDDとTest Code

## TDD（Test-driven devlopment）

#### Test Code
TDDに入る前、先ずTest Codeについて知っておきたい。
Test Codeとは、サービスの品質を確認したりバグを見つけるため作成するコードで、サービスが期待どおりに動作しているのか確認できる。
Test Codeのない状態のテストより時間の節約ができるメリットもあるし、初めてコードを見た開発者がTest Codeを通じて、コードの動作を少し簡単に理解できるようにする文書にもなる。

---
#### TDD
1. **定義**
TDDは、開発が完了した後テストを行う方法ではなく、テストをして開発するプログラミング方法。つまり、まずTest Codeを作成し、そこに合格するためのコードを作っていく方法を意味する。
![gg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662678/9f4e677d-1208-558c-d14f-0bf049b53c58.png)
![21c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662678/b1f22b12-8d14-30c6-71bc-eab018da8d92.png)

2. **メリット**
（1）コード作成前、具体的に設計することが可能
　　：TDDは具体的に設計を強制し、自分が何をどのように作るべきかを明確にしてくれる。
（2）エラーの素早かな把握とデバッグ時間の短縮
　　：どの部分に問題が発生したかを明確に把握できるため、より迅速な修正が可能になる。
（3）文書（説明書）の役割
　　：テストコードは、設計者が何の意図を持って書いたのか、どんな結果を予想したのかが
　　　見えるため、設計者の意図が十分に把握することができる。


3. **デメリット**
（1）事前準備期間が必要
　　 ：TDDをプロジェクトに導入するには、事前に必要な知識を習得し、
　　　開発環境を構築する必要があるので時間がかかる。
（2）生産性の低下
 　　：開発時間が短いプロジェクトの場合、TDDを使用してテストコードを作成し、
　　　それに合わせてコードを作成すると、時間がかかり、非効率的になりかねない。

4. **@SpringBootTest**
SpringBootでの統合テストのためのアノテーションで、全体的なFlowのテストに適切。

5. **JUnit5**
JUnitはTDDの代表的なToolで、世界中で最も多く使用されている「Javaユニットテストフレームワーク」である。特にJUnit5はJava8以上から使用可能で、JUnit Platform、JUnit Jupiter、Junit Vintageが組み合った形である。@Testを付けることで、テストメソッドであることが宣言できる。
【Kotlin】続・引数がデフォルト引数か否かを判定する

# 前書き
`Kotlin 1.7`まででは、引数がデフォルト引数か否かを判定する方法が公式には提供されていません。
引数がオブジェクト型のみという制約を付けられるなら、以下の記事の方法で対応可能ですが、この方法は[今後利用できなくなる可能性があります](https://qiita.com/wrongwrong/items/4dae826b7de31b1f36c3#%E8%BF%BD%E8%A8%98)。

https://qiita.com/wrongwrong/items/4dae826b7de31b1f36c3

そこで、この記事ではどれだけコードが汚くなってでも引数がデフォルト引数か否かを判定する方法を考えてみます。
この方法はリフレクション等の魔法を用いずに実現可能な範囲で、プリミティブ型にも対応しています。
ただし、かなり非現実的なコードになっています。

# サンプルコード
以下の`Sample`クラスでは、コンストラクタに引数を指定したか否かを`fooSpecified`/`barSpecified`に格納しています。

```kotlin
class Sample(
    ctxt: DefaultProvider = DefaultProviderImpl(),
    val foo: Int = ctxt.fooDefault,
    val bar: String? = ctxt.barDefault
) {
    sealed interface DefaultProvider {
        val fooDefault: Int
        val barDefault: String?
    }
    private class DefaultProviderImpl : DefaultProvider {
        var fooSpecified: Boolean = true
            private set
        override val fooDefault: Int get() {
            fooSpecified = false
            return -1
        }

        var barSpecified: Boolean = true
            private set
        override val barDefault: String? get() {
            barSpecified = false
            return null
        }
    }

    val fooSpecified: Boolean
    val barSpecified: Boolean

    init {
        val ctxtImpl = ctxt as DefaultProviderImpl

        fooSpecified = ctxtImpl.fooSpecified
        barSpecified = ctxtImpl.barSpecified
    }
}
```

```kotlin:利用例
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

@Test
fun 引数指定無し() {
    Sample().apply {
        assertFalse(fooSpecified)
        assertFalse(barSpecified)
    }
}

@Test
fun 引数指定あり() {
    Sample(foo = 1, bar = "2").apply {
        assertTrue(fooSpecified)
        assertTrue(barSpecified)
    }
}
```

## 解説
`Kotlin`では、デフォルト引数に別のデフォルト引数を用いた値を設定できます。
サンプルコードではこれを利用して、`DefaultProviderImpl`にデフォルト引数の利用状況を記録しています。

## 考察
まず第一の残念ポイントは、コードが非常に複雑になってしまうことです。
手動で一々こんなものを書いていられません。

第二の残念ポイントは、`DefaultProvider`が必ず第一引数に来てしまうため、利用側が実質的に名前付き引数の利用を強制されてしまう点です。
`Kotlin 1.7`現在、デフォルト引数同士の参照は順番の制約が有るため、どうしてもこうなってしまいます。
これが無ければ、使う側が何か意識する必要が無くなったんですが……。

ということで、コード生成するならワンチャン無い位の仕上がりとなりました。
強大な黒魔術に手を染めれば、使い手的にスマートな見栄えは実現できなくもない気がしますが、流石にそこまでやる気にならなかったのでここまでとします。
GoのError()とString()の優先順位

:::note info 
Go 1.18
:::

Go初心者です。
A Tour Of Go
Stringer～Errorsをやっていた。https://go-tour-jp.appspot.com/methods/19

> Goのプログラムは、エラーの状態を error 値で表現します。
error 型は fmt.Stringer に似た組み込みのインタフェースです:
>```go
>type error interface {
>    Error() string
>}
>```
> ( fmt.Stringer と同様に、 fmt パッケージは、変数を文字列で出力する際に error インタフェースを確認します。 )

つまり、fmt.Print(f)をしたときに、`f`のメソッド`String()`と、メソッド`Error()`を探しに行き、その文字列を（Printなら改行なしで）プリントする。
では、以下のように、String()とError()両方をもつインタフェースをfmtが呼び出したときにはどうなるか。

```go
package main

import "fmt"

type MyType string

func (h MyType) String() string {
	return "ストリング"
}

func (h MyType) Error() string {
	return "エラー"
}

func main() {
	f := MyType("fuga")
	fmt.Print(f)
}

```

これは、
`エラー`
が出力される。

`fmt`の中を見てみよう。どうやってString()やError()を探しにいっているのか。
fmt.Print(f)をデバグすると以下のように、`fmt/print.go`の`printArg`が呼び出されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317324/59a60bdc-0f4c-3181-b94a-569c52551c47.png)

こちらで、`type switch`を用いて引数の型別に処理を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317324/7122a200-659f-097c-78a3-ea4ae05a6fd0.png)
（省略）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317324/041fc2f0-03be-73dc-66d9-fc40f2fff2a6.png)

当然、MyTypeはcaseにないので、defaultまで落ちてくる。（一瞬、MyTypeの根底はstringなので`case string`に引っかかるのかと思ったが、MyTypeはstring型の値を保持しているだけで、MyTypeはstring型ではないので、引っかからない）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317324/900fbe84-17a2-2715-b762-03facc926f5f.png)

`default`では、`handleMethods`を呼び出している。

途中省略してるが、errorとStringerの分岐はここにあった。case errorが先に書かれているので、当然Error()とString()両方持っているタイプはfmtではerrorとして扱われる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317324/081a442b-e045-14e2-5660-1921d5d000b2.png)

やはり両方のメソッドを持っているパターンは思い浮かばないが（というかError()と別の文字列表現がわざわざほしい、みたいなケースなので相当まれか

まあ、中身が少しわかったのでよしとします。
JavaScript で 3 秒待ちたい

- [あるWebサービスの開発メモ・目次ページに戻る](https://qiita.com/ishi32/items/152a1ecf7eeee7a8fb57)
- [あるWebサービスの開発メモ・JavaScript チートに戻る](https://qiita.com/ishi32/items/aa1db70e2176652dc97f)

怪しいループを書いたときに

「このループが抜けてこなかったらマズいな」

「従量課金、大丈夫かな？」

といった不安を感じる時って、だいたい失敗しています。ログ出力が追いつかないほどクライアントサイドでブン回ってしまうと収拾がつかなくなってしまいます。

そこで Wait の登場です。

実装方式はいろいろと検討してみましたが、どれも私にはわかりにくい実装でした。[こちらの先生](https://laboradian.com/js-wait/) が公開してくれている async function を利用するものがとてもわかりやすかったので、実装と動作確認をおこなってみました。

(指定された時間待つだけの関数を内包したPromiseオブジェクトを返す関数を用意する)

```
  const wait = (msec: number) => {
    return new Promise((resolve, reject) => {
      setTimeout(resolve, msec);
    });
  };
```

(上記の関数とその後で実行したい処理を async を付けた関数に記述する)

```
  async function waitAfterCall() {
    try {
      await wait(3000);
      // ここに目的の処理を書く
    } catch (err) {
      console.error(err);
    }
  }

  waitAfterCall();
```

async function は ECMAScript 2017 (ECMA-262) で追加された機能なので使えないブラウザがあるのかもしれません。読みにくいけど確実な実装も用意しておきたいところですが、そうなった時に考えようかな、と思っているところです。
codecommitでfilter-branchが動かないので、filter-repoを使った

codecommitでfilter-branchで消える人もいるのかもしれないが。
Gitに間違ってファイルを間違ってあげた時にfilter-branchを今まで使ってた気がする。
なぜか全然ファイルが消えないので、filter-repoを使ったら消えたって話。


```
brew install git-filter-repo
```


```
いらないファイル削除
git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
いらないファイル削除（例　password.txtを消す)
git filter-repo --path password.txt --invert-paths
いらないファイル削除（例　--partialで全部ブランチから消す)
git filter-repo --path password.txt	--invert-paths --partial


git remote add origin https://github****

originに反映
git push origin --force --all

```


下記は動かなかったコード達
何故かoriginのファイルが消えなかった。

```
git filter-branch -f --index-filter 'git rm -f --cached --ignore-unmatch password.txt' HEAD --all

git filter-branch -f --index-filter "git rm --cached --ignore-unmatch 'password.txt'" HEAD
git push --force origin main

git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch 'password.txt'" \
  --prune-empty --tag-name-filter cat -- --all

```
WSLのフォルダをエクスプローラーで開けない

ネット記事を漁り、wslの環境構築をしていたのですが、1つ大きな問題が発生。

エクスプローラー上でwslのフォルダが開けませんでした。

アドレスバーに「¥¥wsl$」と入力すれば、アクセスできるということだったのですが、僕の環境では以下のようなエラーが発生。

![wslerr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159574/a1eb0773-61a4-9c09-fa85-22fd2519015a.png)

エラーで検索をかけ、同じエラーにぶつかった人の記事を見ながらいろいろ試してみましたが、どれを試してもうまくいきませんでした。

Qiitaでも皆さんに助けを求め、知恵をお借りしながら対応してみたのですが、なかなか解決しませんでした。

数日経ち、ついに正解にたどり着きました。

レジストリにP9NPというやつが足りてなかったようです。

「レジストリ？」など聞き覚えもないし触ったこともなかったので、本当にこれが原因なのか疑問がありましたが、丁寧に教えてくださった方がいたのでご享受していただいた通りに実行してみました。

まず、powershellを管理者権限で開き、以下のコマンドを発行します。(出力された値は念のためメモしておいてください。)

```
(Get-Item 'Registry::\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order').GetValue('ProviderOrder')
```

次に、以下のコマンドを打つことで、P9NP,RDPNP,LanmanWorkstation,webclientに設定することができます。

```
Set-ItemProperty "Registry::\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order" -name ProviderOrder -value "P9NP,RDPNP,LanmanWorkstation,webclient"
```

これを実行したのち、もう一度エクスプローラーでwslのフォルダにアクセスしたところ、ついに中身を見ることができました。

ちなみに、中国にも同じエラーで躓いている方がいらっしゃいました。
https://www.superheaoz.top/2021/10/50200/
yarnでパッケージのバージョンを下げたい時のコマンド

はじめに
--
作成中のポートフォリオのフロントをreactを使って開発しています。
色々な記事を参考にしながら開発をしている時に、ルーティングの設定でSwitchが使えないというエラーが起きました。

原因はreact-router-domの6系へのバージョンアップに伴って、機能の名前が変更されたことでした。（SwitchからRoutesに)
参考にする記事が5系での記述が多く、まずはreactに慣れるために6系から5系にダウングレードを行ったので、備忘録として残します。


yarnでreact-router-domをグレードダウン
---
下記がバージョンを変更する際のコマンドです。
ダウングレードなのにupdateで変更できてしまうのも変な感じですね。

~~~
yarn update パッケージ名@指定したいバージョン
~~~

ちなみに今回僕が叩いたコマンドは下記になります。
~~~
#実際に叩いたコマンド
yarn upgrade react-router-dom@5
~~~

ちなみにnpmだと一回アンインストールしてからバージョンを指定して再度インストールしないといけないみたいです。

終わりに
--
無事変更をして、Switchを使用することができました。
reactをスラスラかけるようになるために頑張ります。
Linux パーティションについて２




Linuxをインストールする際、パーティションを設計する必要があります。パーティションとはハードディスクを論理的に分割した単位のこと。

Linuxのパーティションには、以下の2つが最低限必要。

●ルートパーティション
最上位のディレクトリであるルートディレクトリ(/)を割り当てたパーティションのことで、その配下に様々なディレクトリやファイルが含まれています。

●スワップ領域
物理メモリに収まらなかった情報を一時的に格納する為の領域です。

上記の最低限必要なパーティションのみを作成した場合、全てのディレクトリがルートパーティションに収まることになります。しかし、通常はディレクトリの用途に応じて、特定のディレクトリを別のパーティションに割り当てます。特に読み込みや書き込みが頻繁に発生するディレクトリに専用のパーティションを割り当てる事が多いです。

専用のパーティションを割り当てることによって、障害時の被害を、障害が発生したパーティション内に抑えられる可能性があります。また、Linuxでもパーティション毎のバックアップやリストアが可能ですので、バックアップしたいディレクトリに専用のパーティションに割り当てておくと、それらの作業も容易になります。

なお、システムの起動に必要なディレクトリ(/bin、/sbinなど)はルートパーティションから分割することはできません。

主なディレクトリ
・/home 一般ユーザのホームディレクトリ（書き込みが頻繁に発生）
・/usr 軌道には不要なプログラムなどを格納（読み込みが頻繁に発生）
・/var ログファイルやメールなど可変ファイル郡を格納（書き込みが頻繁に発生）
・/opt 追加でインストールしたパッケージを格納（容量が大きくなる可能性がある）
・/boot Linuxカーネルなど起動に必須のファイルを格納
・/tmp 一時ファイルを格納
・/bin 一般ユーザ用のコマンドを格納
・/sbin 管理者用のコマンドを格納
・/etc システムの設定ファイルを格納
・/lib 共有ライブラリを格納
・/dev デバイスファイルを格納


●MBR形式、GPT形式のパーティションテーブルをサポートするパーティション操作コマンドはpartedです。partedは以下のパーティションテーブルをサポートしています。
・bsd
・loop (raw disk access)
・gpt
・mac
・msdos
・pc98
・sun

partedコマンドの書式
parted [ -l ] デバイスファイル名

「-l」オプションはすべてのデバイスのパーティションテーブルを表示します。パーティションテーブルにはパーティションの情報が格納されています。

partedコマンドの呼び出しは、以下の点でfdiskと異なりますので注意が必要です。
・デバイスファイル名を指定しない場合、fdiskは処理を行わずコマンドヘルプを表示しますが、partedでは検出した最初のブロックデバイスを自動で選択します。
・「-l」オプションは、fdiskは表示するデバイスを指定できますが、partedでは指定は無視され、すべてのハードディスクの情報を表示します
partedはfdiskと同様の対話型ツール、


help を入力すると、使用できるサブコマンドの一覧が表示されます。


主なサブコマンド：
・mklabel、mktable 新しいパーティションテーブルを作成する
・mkpart 新しいパーティションを作成する
・rm パーティションを削除
・print(勝楽系：p)　パーティションテーブルの情報を表示する
・quit(省略形：q)　partedでの作業を終了する

●partedコマンドで新しいハードディスクにパーティションを作成するには、

１．パーティションテーブルの指定
mklabel サブコマンドで、パーティションテーブルの方式を指定します。未指定の場合MBR形式として動作します。

mklabel サブコマンドの書式

(parted) mklabel [ パーティションテーブル ]

MBR形式を明示的に指定するには、msdosを指定します。


GPT形式とする場合はgptを指定します。


２．パーティションの作成
mkpartサブコマンドで、パーティションを作成します。
mkpartサブコマンドの書式

(parted) mkpart [ パーティションタイプ ファイルシステム種別 パーティション名 ] 開始位置 終了位置

パーティションタイプはMBR形式で指定可能で、primary（基本）、extended（拡張）、logical（論理）を指定します。

以下の例ではGPT形式のハードディスクに100MBの領域を2つ作成しています。作成されたパーティションの情報は、printサブコマンドで確認します。


partedでの編集結果は即時反映されます。そのため、特に書き込み指示などなしで quit で終了させます。


このあとは従来通り、作成したパーティション上にmkfsコマンドによるファイルシステムの作成を行います。

なお、partedコマンドは対話形式ではなくサブコマンド指定で直接パーティション編集を行うことも可能
WEBシステムの疎通確認をLambda+Slackでメンション飛ばす


PythonでSlack通知を作る。
AWSのLambdaとかで通知をするときに、メンションつけたい時あるよね。
@channelじゃダメで<!channel>を使うと良いよ。


```Python:NGなコード
message = "@channel 疎通できませんでした！"
request.post(message)
```

```Python:OKなコード
message = "<!channel> 疎通できませんでした！"
request.post(message)
```


```
チャンネル参加者すべて
@channel
<!channel>

アクティブな参加者すべて
@here
<!here>	

メンバーすべて
@everyone
<!everyone>	

```
Mapbox GL JS クラスター化したポイントの情報を得る

mapboxにはclusterという非常に便利な機能があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/1905c9f0-7d3d-c8c7-f442-f1357dddff5f.png)　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/cc65f14b-753e-51ee-c7f1-83f073c39cf7.png)
マップ上に配置した情報を、ズームアウトすることで自動的にいい感じにまとめてくれるんです。

いい感じにまとめてくれた情報を引き出すためには、

```
    map.addSource('populations', {
        cluster: true, // clusterあり
       :
        clusterProperties: { // cluster化したときに使用する
            'sump': ['+', ['get', 'p50']], // properties['p50']を合計したものがsumpに入る
       :

    map.addLayer({
        id: 'cluster-point',
        type: 'circle',
        source: 'populations',
        filter: ['has', 'sump'], // cluster化しているときにのみ持っている
       :

    map.on('click', 'cluster-point', (e) => { // cluster化した点をクリックした
        const coordinates = wrapCoodinate(e);
        const props = e.features[0].properties;
        new mapboxgl.Popup()
            .setLngLat(coordinates)
            .setHTML( `合成数${props['point_count']}<br>総人口${props['sump']}<br>` )
            .addTo(map);
    });


       :
function wrapCoodinate(e){ // 位置を合わせるための処理
    const coordinates = e.features[0].geometry.coordinates.slice();
    // Ensure that if the map is zoomed out such that
    // multiple copies of the feature are visible, the
    // popup appears over the copy being pointed to.
    while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
        coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
    }
    return coordinates;
}

```

こんな感じで、cluster化したときに使用するプロパティが```e.features[0].properties```に入っています。
また、いくつのポイントがクラスター化したのかは```point_count```に自動的に入るようです。
超簡単【お家で交通系ICのピッを楽しむ方法】obniz

### はじめに
小さい子からすると、ICカードでピッてするの憧れですよね。
でも本物だとそんなに何度もできないので、、、
obnizで手間なく目的のものができたので記事にしました。
とにかく簡単です。

https://twitter.com/i/status/1559153708168257536

### 準備するもの
obniz Board
USB micro B cable
ブザー　Keyestudio_Buzzer
距離センサー　HC-SR04
（全て[obnizスターターキット](https://obniz.com/ja/products/starterkit)に含まれています。）

改札機のピッの部分を印刷した紙（センサー部分はくり抜いておく）

### 実装
ブザーとセンサーをコードで指定した番号(今回はセンサーを0〜３、ブザーを9〜１１）に差し込み、コードを開発者コンソールにコピペして実行を押すのみです。
obnizの準備は[公式HP](https://obniz.com/ja/doc/reference/board-1y/quick-start/)を参考にします。

### コード
```html
<html>
  <head>
    <script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
  </head>
  <body>
    <script>
      var obniz = new Obniz("obnizID"); // ここに自身のobniz IDを入力する

      obniz.onconnect = async function () {
        var hcsr04 = obniz.wired("HC-SR04", {
          gnd: 0,
          echo: 1,
          trigger: 2,
          vcc: 3,
        });

        var speaker = obniz.wired("Keyestudio_Buzzer", {
          signal: 9,
          vcc: 10,
          gnd: 11,
        });

        obniz.repeat(async () => {
          const distance = await hcsr04.measureWait();
          console.log(distance);

          if (distance < 50) {
            // 5cm未満でピッ
            speaker.play(675);
            await obniz.wait(20);
            speaker.play(675);
            await obniz.wait(20);
            speaker.stop();
          }
        }, 0);
      };
    </script>
  </body>
</html>
```

### うまく動かない場合
- obniz IDはご自身のものを入れましたか？
- 差し込む番号は間違えていませんか？
- obnizが安定した電源につながっていますか？
- 前に実行中のものが残っていませんか？

エラーを確認したい場合は、新しいタブで実行し、開かれたタブ内で
右クリックで「検証」。
右上に赤い✖️マークがついているところを押すとエラー内容が表示されます。
![スクリーンショット 2022-08-17 0.09.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653579/00f4bc4d-7c2e-d8c5-a689-4b0a58e4c0bb.png)
<img width="300" alt="スクリーンショット 2022-08-17 0.06.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653579/20a682af-9833-28da-6d79-009a6d2acb81.png">
![スクリーンショット 2022-08-17 0.09.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653579/d9363d27-c28f-1f6d-fd00-3522c3a141df.png)


### 娘の反応
何度かピッとした後、本体に興味を示し破壊してゆきました　笑。
Windows11 TeraTermでEC2にssh接続する

# Windows11 TeraTermでEC2にssh接続する

最近、AWSを習得するためにAWSのサービスをいくつか触っているのですが、ちょっとやって頭からするする抜けていくばかりだったので腰を据えて理解を定着させるために備忘録的なものを残そうと思います。

今回はその１つめ。

## 前提環境

* Windows11
* TeraTerm4.106

TeraTermダウンロードページ

https://ja.osdn.net/projects/ttssh2/downloads/74780/teraterm-4.106.exe/

## EC2インスタンスの起動

今回は接続確認ができたら消してしまおうと思うので、以下の設定で作成しました。

* AMI - Amazon Linux2 AMI (HVM) - Kernel 5.10, SSD Volume Type
* インスタンスタイプ - t2.micro （nanoでもよかったかも）

### キーペアを作成する

新規でキーペアを作成します。（EC2インスタンスを消すのと同時に破棄します。）

`my-ec2-study-s3-access1.pem` という鍵を作成しました。

## TeraTermをインストールする

次の記事を参考にインストールしました。

https://dev.classmethod.jp/articles/aws-beginner-ec2-ssh/

## TeraTermでEC2に接続する

### 必要となるもの

* EC2のパブリック IPv4 アドレス（ `***.***.***` ）
* ユーザー名：ec2-user
* キーペアの秘密鍵： `my-ec2-study-s3-access1.pem`

### 接続する

1. TeraTermを起動
2. ファイル＞新しい接続
3. ホスト：EC2のパブリック IPv4 アドレスを入力 `***.***.***`
4. ユーザー名：ec2-user
5. 認証方式：RSA/DSA/ECDSA/ED25519鍵を使うを選択
6. ダウンロードされたpemファイルを選択
7. [OK]

これでssh接続が成功しました。思ったより簡単に接続できた印象です。ssh接続の認証周りやファイルのパーミッションなんかで詰まるかと思ったのですがそんなこともなく、TeraTermべんり！

EC2のインスタンス起動も結構速くてするする進んだ印象でした。

# 参考記事

https://dev.classmethod.jp/articles/aws-beginner-ec2-ssh/
Docker上にOracle環境を構築してみた


## 今回使用したOracleのバージョン
バージョン：19.3.0
zipファイル名：LINUX.X64_193000_db_home.zip

## 途中つまずいた点
* イメージビルドに失敗
→ オラクル公式サイトからダウンロードしたzipファイルの配置場所が間違っていた。
ダウンロードしたOracleのバージョンと同じディレクトリ直下に配置する必要があったが、異なるバージョンのディレクトリに配置してしまっていた。
* イメージビルドが不完全で、コンテナ作成時にうまくいかなかった。
→ Docker Desktopのメモリ不足が原因。2GB→4GBに変更してから、イメージを再作成したらうまくいった。
* コンテナ作成できたが、ログインができなかった。
→ docker exec コンテナ上のサービス名 sqlplus SYSTEM/Oracle19@ORCLCDB
だとすぐ接続が解除されてしまった。
→ docker exec に　-itオプションを入れることで、うまくいった。

```
docker exec -it コンテナ上のサービス名 sqlplus SYSTEM/Oracle19@ORCLCDB
``` 
```:
具体例
docker exec -it dockerfile1_db_1 sqlplus SYSTEM/Oracle19@ORCLCDB
```




## 参考URL
* [Oracle Database 19c 環境をDockerで作成してSQL Developerで接続する](https://zenn.dev/msksgm/articles/20211225-oracle-database-19c-docker)
* [DockerでOracle19cを構築しようとした際に発生したエラー](https://qiita.com/shiba_it/items/e940369e29bc9a89d230)
* [GitHub](https://github.com/oracle/docker-images/issues/1257)
* [DockerでOracle Databaseを使う](https://qiita.com/gorilla0513/items/f22e8cce4e08da031abe)
SSHログイン時のメッセージ表示を消したい＆任意のメッセージを表示したい

# はじめに
RedHat8.4で構築したLinuxサーバにSSHログインした際、Web ConsoleやRedHat Insightのメッセージが表示された。これらをアンインストールすることなく表示を削除する。

表示内容はこんな感じ。
~~~console:
# ssh localhost
root@localhost's password: 
Web console: https://srv01:9090/ or https://192.168.0.2:9090/

This system is not registered to Red Hat Insights. See https://cloud.redhat.com/
To register this system, run: insights-client --register

Last login: Tue Aug 16 20:24:41 2022 from 192.168.0.1
[root@srv01 ~]#
~~~

# motd.dファイルの動作
SSHログイン時にmotd.d配下のファイル内容が順番に表示される。
ファイルはシンボリックリンクになっていて、インストールしたアプリがお知らせを表示したいときに使用されているらしい。
アプリ側の構築状況によって表示を変えられる、というか変わっていたのでそのような使い方もできる。

~~~console:
[root@srv01 ~]# cd /etc/motd.d/
[root@srv01 motd.d]# ll
合計 0
lrwxrwxrwx. 1 root root 17  3月 12  2021 cockpit -> /run/cockpit/motd
lrwxrwxrwx. 1 root root 41  8月 16 14:41 insights-client -> /etc/insights-client/insights-client.motd
~~~


~~~console:
[root@srv01 motd.d]# cat cockpit 
Web console: https://lidvp010:9090/ or https://172.21.133.2:9090/

[root@srv01 motd.d]# cat insights-client 
This system is not registered to Red Hat Insights. See https://cloud.redhat.com/
To register this system, run: insights-client --register

~~~

# motd.dファイルを削除
motd.d配下ファイルがSSHログイン時に表示されるため削除する。

~~~console:
[root@srv01 motd.d]# rm cockpit insights-client 
rm: シンボリックリンク 'cockpit' を削除しますか? y
rm: シンボリックリンク 'insights-client' を削除しますか? y
~~~

ファイル削除後にSSHログインすると何も表示されなくなった。
~~~console:
# ssh localhost
root@localhost's password: 
Last login: Tue Aug 16 21:49:47 2022 from 127.0.0.1
[root@srv01 ~]# 
~~~

# まとめ
Linuxでお馴染みのSSHで、ログイン時のメッセージ表示を削除してみた。逆に任意のメッセージを表示することも容易なので便利に使いたい。
AWS入門用にEC2-ApacheでHP公開してからやったこと

# AWS入門用にEC2-ApacheでHP公開してからやったこと


## 記事の内容

[初めてEC2を触ってみたので手順をまとめた](https://qiita.com/gnk263/items/27323fe3103a2a59ba27)
こちらの記事を参考にEC2でApacheを起動し簡単なページを表示した後にやったことをまとめた。


## 目的

セキュリティを強化する。
勉強用にいくつかのサービスを触ってみる。


## 背景

業務系アプリケーションエンジニアが私用で簡単なHPを公開する必要があった。
加えて近日中にCertified Cloud Practitioner 認定を受験する予定だが、似たような名前のサービスが多く覚えるのが大変だったため、勉強がてらAWSで環境構築することにした。
静的WEBサイトの公開だけならS3でもできるが、本業がwebアプリのSEなので、後学のためApacheで公開した。
- __できるだけプラクティスに沿ったものの、あくまで勉強用ということで、そのまま本番環境で使う類のものではないことをご理解ください。__
- __料金はよく確認してください。__


## やったこと


### Apacheの設定

Apacheを産まれたままの姿で晒しておくと危険なので色々設定する。
「apache やっておいたほうが良い」などで検索して出てきた対策を実施する。
AWSに関係なく勉強になった。


### EC2 セキュリティグループの設定

インバウンドルールの タイプ:SSH を0.0.0.0/0にしていたので自宅のIPに変更
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779586/029f2618-8b18-fd21-45dd-f9a5196b40fb.png)


### IAM

> ID と AWS のサービスおよびリソースへのアクセスを安全に管理する

[AWS Identity and Access Management (IAM)](https://aws.amazon.com/jp/iam/)

#### ルートユーザーの設定

ルートユーザーは極力使わずログインを困難にしておくといいらしい。
![スクリーンショット 2022-08-15 225311.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779586/3a025f6d-1756-1d10-5555-3da6cf7a2690.png)
IAMを起動すると真っ先に表示されるダッシュボードにrootユーザーのログインに関するセキュリティのチェック結果が表示されている。
上の画像では設定後なのでグリーンになっているが赤くなっていたら指示に従い設定を進める。

#### HP管理用ユーザーの作成

HPの日常管理用のユーザーを作成する。
手順は

1. グループ"hp-creators"を作成
1. ポリシーをグループ"hp-creators"にアタッチ
1. ユーザー"hp-creator"を作成してグループ"hp-creators"に追加

このスタイルがベストプラクティスらしい。ということで実施。
ポリシーは精査する余裕がなかったのでテンプレートから _AmazonEC2FullAccess_ なるものを選んだ。本来であれば必要最小限の権限だけを与えるべきだ。


### AWS Sheild

> マネージド型の DDoS 保護

[AWS Sheild](https://aws.amazon.com/jp/shield/)

Standardは自動的に有効化されるとのこと(202208時点)。



### Amazon Inspector

> 大規模な自動化された継続的な脆弱性管理

[Amazon Inspector](https://aws.amazon.com/jp/inspector/)

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779586/f38a4dd8-026a-3bdf-6cac-0d17afa03679.png)
omg


### AWS Trusted Advisor

> コストを削減、パフォーマンスを向上、セキュリティを強化

[AWS Trusted Advisor](https://aws.amazon.com/jp/premiumsupport/technology/trusted-advisor/)

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779586/580f78e6-b4dd-4f83-6490-0298a59f7279.png)


### Amazon CloudWatch

> AWS とオンプレミスにおける AWS のリソースとアプリケーションのオブザーバビリティ

[Amazon CloudWatch](https://aws.amazon.com/jp/cloudwatch/)

かっこいいグラフを見ることができる。


### AWS Billing

> 毎月の AWS 請求書を簡単に理解する

[AWS Billing](https://aws.amazon.com/jp/aws-cost-management/aws-billing/)

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779586/a6dc402d-4087-6150-4aa9-85ddb0b6a243.png)
ふ～ん


## 感想

セキュリティが強化されて少し安心できた。
一度触ったサービスのことはそうそう忘れないので勉強になった。
TCL commands

### Transaction（Tx）
Transactionについては[以前投稿した](https://qiita.com/KyungJoon960/items/1c948e158aabadf74302)ので簡単に言うと、
データベースの論理演算単位であり、分離できない作業の最小単位のこと。
@Transactional をクラスやメソッドに貼り付ける場合、該当範囲内のメソッドがTxになることを保証してくれる。

### TCL（Transaction Control Language）
データベース内のTxを管理するために使用される。このTCLの代表的コマンドが以下の3つ。


1. COMMIT
変更されたデータをDBに永続的に保存するために使用。

2. ROLLBACK
DBを最後にCommitされた状態に復元するコマンド。Windowsで言うとCtrl＋Zのみたいかも。

3. SAVEPOINT
Savepointを設定すると、最後のCommit全体をRollbackするのではなく、現時点からSavepointまでのTxだけをRollbackすることができる。
 
```
SAVEPOINT SavePoint名; // SavePointの設定
```

```
ROLLBACK TO SavePoint名; // SavepointまでRollback
```
コード譜投稿アプリを作る #1（アプリ構築）


[←前回の記事](https://qiita.com/t_sekky/items/de8768b9826d98601164)

今回はひとまずRailsのAPIモードとNext.jsのアプリケーションを作っていきます
環境はM1macです


## Railsアプリ作成
[この記事](https://qiita.com/ydammatsu/items/a2fbae968149bf2c1999)に書いてあることを~~コピペ~~参考にしてdockerを使って構築しました
ruby3系とRails７系は初めてだけど試すのには絶好の機会だしまぁええでしょ

詰まった点としては`db:create`する際に以下のようなエラーが出ました
```
/lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by /usr/local/bundle/gems/nokogiri-1.13.0-aarch64-linux/lib/nokogiri/3.1/nokogiri.so) - /usr/local/bundle/gems/nokogiri-1.13.0-aarch64-linux/lib/nokogiri/3.1/nokogiri.so
```

エラーを読むと`force_ruby_platform`を`true`にしてくれとのことだったので
```Dockerfile:Dockerfile
gem install bundler && bundle install
```
↑の部分を
```
gem install bundler && bundle config set force_ruby_platform true && bundle install
```
に変更したところ動きました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664809/772cd125-b667-579c-260a-c0bca17228c0.png "http://localhost:3000/")
なんかいつものyay!じゃないけど動いてそう


## next.jsアプリ作成
[この記事](https://tech.smartcamp.co.jp/entry/vercel-and-heroku-dev)を参考に作りました（先人には感謝）
変えたところはサーバー側のポートと競合するので、
```yaml:package.json
...
  "scripts": {
    "dev": "next dev -p 3001",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
...
```
上記のようにnextアプリのポートは3001番を指定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664809/1b9bfd9b-3995-036a-6ffa-7f3ebc507676.png)
表示完了。
nodebrewインストールメモ


nodebrewインストール方法
忘れるのでメモ。

## nodebrew インストール

```bash
$ brew install nodebrew
$ nodebrew setup
Fetching nodebrew...
Installed nodebrew in $HOME/.nodebrew

========================================
Export a path to nodebrew:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================

# 上記で setup したときに表示されたコマンドを .bash_profile に追記
$ echo "export PATH=\$HOME/.nodebrew/current/bin:\$PATH" >> ~/.bash_profile
$ source ~/.bash_profile

# インストールしたいバージョンを下記から選択
$ nodebrew ls-remote

# node.js インストール
$ nodebrew install v10.15.3

# インストール内容確認
$ nodebrew ls
v10.15.3

current: none

# インストールしたバージョンを使用可能にする
$ nodebrew use v10.15.3

# 使用可能になったか確認（current のところ）
$ nodebrew ls
v10.15.3

current: v10.15.3

# バージョン確認
$ node -v
$ npm -v

# 困ったらヘルプを見る
$ nodebrew help
```
MacOS Montereyでローマ字入力プロセスをkillallする方法

## 結論

以下のコマンドでローマ字入力プロセスを止めて再起動させることができます。

```bash
killall -HUP JapaneseIM-RomajiTyping
```

なお、かな入力を使っている方は以下のコマンドで再起動できます。

```bash
killall -HUP JapaneseIM-KanaTyping
```

## 上記に至った経緯

コマンドラインから日本語入力時も半角で数字を入力できるようにする設定をしたあと、適用するためにローマ字入力のプロセスを再起動しようとしましたがエラーが発生しkillできないという事象が発生しました。

設定を変更するコマンド

```bash
defaults write com.apple.inputmethod.Kotoeri JIMPrefFullWidthNumeralCharactersKey -float 0
```

プロセスを再起動させるコマンド

```bash
killall -HUP JapaneseIM
# => No matching processes belonging to you were found
```

`JapaneseIM` というプロセスは存在せず、コマンドに失敗してしまいます。

```bash
ps axo command, | grep "[J]apaneseIM"
# => /System/Library/Input Methods/JapaneseIM-RomajiTyping.app/Contents/PlugIns/JapaneseIM-RomajiTyping.appex/Contents/MacOS/JapaneseIM-RomajiTyping -AppleLanguages ("ja-JP")
```

どうやら `JapaneseIM` から `JapaneseIM-RomajiTyping` に名前が変更されたようです。

`JapaneseIM-RomajiTyping` に変更してコマンド実行すると成功し、無事設定を反映させることができました。

```bash
killall -HUP JapaneseIM-RomajiTyping
```


## 参考にした記事

- https://baqamore.hatenablog.com/entry/2016/05/21/114732
SPD図についてのメモ

# はじめに

- SPD図とは？？
    - NECの中の人が開発した構造化チャート図法
        - Structure Programing Diagramの略称
    - 要求仕様や業務分析から詳細設計まで使用できるチャート図
        - 同様の図法にはPAD、HCPなどがある

## 特徴として

- SPDの記号が他の図法に比べて非常にシンプルである
    - 各要素の記号がシンプルであり、比較的わかりやすいので可読性が高い
        - 専用のエディタを使用しなくとも作成することができる
        - 罫線文字や記号文字(├・◇)で代用できるので、エディタで簡単に記述ができる
        - MarkDownでの記入も可能である
            - ただし直接記入が必要
        - 応用でプログラムのツリー図やクラスの記述にも利用できる
    - 弱点として
        - 欠点としてネストが増えてきた場合にはメンテナンスがやりづらい傾向にある
        - 古い技術であるので解説本が出版されていたが現在は絶版になっている。
            - ネットでも解説しているサイトがほぼない。

## SPD図の要素について

- 順次
    - ├
    - └
- 分岐
    - ◇-(if:<条件>)
    - │[

- 繰り返し
    - ○-(while:<条件>)

    - SPD図の実際

    ```text
    ○
    ├ 処理１
    ├ 処理２
    ├-◇-(if:<条件>)
    | │[Then]
    | ├ 処理
    | │[Else]
    | └ 処理

    ```

- 個人的にはUMLのアクティビティ図よりもプログラムに近い方法で記述できるので、今でも使える可能性があるのかなと思っております。
    - VSCのプラグインがあれば、使ってみたいなとは思います。
JavaからKotlinの拡張関数を呼び出す

## やること　　　　　　　　　　　　　　　
タイトルの通りです。
JavaからKotlinの拡張関数を呼び出し方を書いていきます。

## どうやるか？
JavaからKotlinの拡張関数を呼び出すときは、`ソースファイル+Kt`という名前のクラスのstatic関数としてコンパイルされる。  
Javaから呼び出す場合は、`this`となるオブジェクトが第一引数となります。　
実際には下記のような感じ。 

Kotlinの拡張関数
```Kotlin:Extension
fun fromJava?.toMapping(): Qiita {
  return Qiita(
    account = this.account,
    username = this.username,
    twitter = this.twitter
  )
}
```

Java
```Java
qiita = ExtensionKt.toMapping(fromJava);
```

以上です。
ROS2:M1 Macの仮想環境(UTM・Ubuntu)で別PCのノードと通信する

## はじめに
Raspberry Piに取り付けたLiDARのデータをRvizで見ようとしたけど動作が重い。そのため別PCでトピックをサブスクライブして見れるようにしようとした際の仮想環境(UTM)のネットワーク設定メモ。

## 使用環境
Raspberry Pi
- Raspberry Pi 4 Model B / 4GB
- Ubuntu Server 20.04.4 LTS
- ROS2 Foxy

M1 Mac(別PC)
- MacBook Air (M1, 2020), macOS Monterey

- [UTM | Virtual machines for Mac](https://mac.getutm.app/)
- Ubuntu Desktop 20.04.4 LTS(64-bit ARMv8/AArch64)
- ROS2 Foxy

# UTMのネットワーク設定を変更してブリッジ接続する
UTMはデフォルトの設定ではネットワーク設定がブリッジになっておらず、Raspberry Piが別PC上の仮想マシンと通信できないため、以下の通りネットワークの設定を変える。
![UTM設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95249/69639243-fbb9-ec27-1047-67619951cd6d.png)
これで別PC上仮想マシンとRaspberry Piが同じセグメントのネットワークに存在するようになり、Raspberry PiのROS2ノードが送信するメッセージを別PC上の仮想マシンがサブスクライブできるようになる。
## 参考記事
[M1-Mac上でUTMでUbuntu-Desktopの仮想マシンを動かす](https://blog.yotiosoft.com/2022/05/28/M1-Mac%E4%B8%8A%E3%81%A7UTM%E3%81%A7Ubuntu-Desktop%E3%81%AE%E4%BB%AE%E6%83%B3%E3%83%9E%E3%82%B7%E3%83%B3%E3%82%92%E5%8B%95%E3%81%8B%E3%81%99.html)
【Express】起動時に、「TypeError: express is not a function」のエラー

expressでサーバー立てようと思い、このように書いていたら、

```typescript
//index.ts
import * as express from "express"; 
const app = express();
```

トランスパイルして実行したところ、こんなことを言われました。
```
/dist/index.js:2
var app = express();
          ^

TypeError: express is not a function
```
※ちなみに、tsconfig.jsonの`module`は、`es6`です。

## 対処法

```typescript
//index.ts
import * as express from "express"; 
//↓
import express from 'express';
```
という記事を見て、真似してみましたが、今度は下のようなコンパイルエラーも出ました。

```
このモジュールは 'export =' を使用して宣言されていて、
'allowSyntheticDefaultImports' フラグを使用する場合は
既定のインポートでのみ使用できます。
```

これについては、tsconfig.jsonにこれを追加してやれば消えます。
```json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true
  }
}
```
これを追加することで、モジュールからのデフォルトのインポートを許可できるそう。
詳しくは勉強中…


## 参考にした記事
https://qiita.com/kozzzz/items/59816861e6a2eb80cb34
https://numb86-tech.hatenablog.com/entry/2020/07/11/160159
https://qiita.com/rhirayamaaan/items/cf3d859678577ec90d7b
Controller, Service, Repository（簡単に）

## Controller, Service, Repository

#### 1. Controller
ClientのRequestを受け取り、どのような処理をするか決定し、サービスに渡す。
#### 2. Repository
DBのリソースを管理し、CRUDを処理する。
#### 3. Service
Controllerから渡されたClientのRequestを処理し、Repositoryに渡す。Repositoryから得られたデータをJava文法に変換後、再びControllerに送る。@Serviceを使用することで、Serviceクラスの設定ができる。

![sss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662678/944ad8e1-ff40-9ff5-e7e7-ceee4e3c7682.png)
【Rails】Javascriptバンドラーの第5の選択肢vite_rails

# 初めに

`Rails7`からアセットパイプラインは`importmap` `esbuild` `webpack` `rollup`の 4 つの選択肢があります。
ですが、新たに`vite_rails`という選択肢をここで紹介させていただきます。

# なぜ vite_rails なのか

- 開発サーバーは非常に高速に起動し、変更が即座に更新される。(ホットリロード)
- 基本的にデフォルトの設定で動作し、構成が簡単である
- デプロイ時は`assets:precompile`でバンドルができる。
- css や sass などもバンドルできる。

# 導入方法

`webpacker`からの移行する方法になります。

`Gemfile`に`vite_rails`を追加します。

```Gemfile:Gemfile
gem 'vite_rails'
```

```console:ターミナル
$ bundle install

$ bundle exec vite install
設定ファイルを作成する
```

デフォルトでは`app/frontend`がエントリーポイントになっていますので、`app/javascript`に変更します。

```json:config/vite.json

{
  "all": {
    "sourceCodeDir": "app/javascript",
  }
  // 省略
}

```

`application.html.erb`にある読み込みのタグヘルパーを変更する。

```erb:app/views/layouts/application.html.erb

- <%= javascript_packs_with_chunks_tag 'application' %>
+ <%= vite_javascript_tag 'application' %>

```

そして、`require.context`を`import.meta.globEager`に書き換える。

```javascript
- const context = require.context("./controllers", true, /\.js$/)
+ const controllers = import.meta.globEager('./**/*_controller.js')
```

# 参考

- [Vite Ruby](https://vite-ruby.netlify.app/)
- [migration to vite - Vite Ruby](https://vite-ruby.netlify.app/guide/migration.html#webpacker-%F0%9F%93%A6)
有益だと思うQiita記事共有（プログラミング勉強法）

# 動機
https://qiita.com/YudaiTsukamoto/items/42a8df22ca4c6b327dfd
を読んで、参考になったため、共有。

# 気づき
まず「理解した」を定義するという項目の、理解が、1から10まで説明出来るを「理解した」と定義することが、特に勉強になった。
自分は未経験だけど、転職したらコードレビューもあるし、書いたコードを1から10まで説明するのはいい練習になると思い、取り入れることにしました。

# 参考記事
https://qiita.com/YudaiTsukamoto/items/42a8df22ca4c6b327dfd
【環境構築】dockerでAlpine Linux（os）だけのコンテナを立ち上げる方法

## 背景
- 必要な環境がdockerhubにない場合、自力でカスタマイズしたdockerfileを作成したい。
- その実験環境として、osのみが入ったコンテナ環境が欲しい。

## 目標
- 最低限のosのみが入ったコンテナを作れるようになる。

## osの選定
- dockerで構築できるos imageは色々ある。
- 今回は、imageの軽量さを重視し、Alpine Linuxを採用した。
※Alpine：Linuxディストリビューションの一つ

## 前提環境
- macOS 11.4 (20F71)
- arm64(M1)

## フォルダ構成
```bash:フォルダ構成
.
├─ Dockerfile
└─ docker-compase.yml
```
## ファイルの中身
```docker:Dockerfile
FROM alpine:3.16.2@sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870

WORKDIR /app
```

```yml:docker-compose.yml
version: '3'

services:
  alpine:
    restart: always
    build:
      context: .
      dockerfile: Dockerfile
    stdin_open: true
    tty: true
    volumes:
      - .:/app
```

## コンテナの起動からコンテナの中に入る
（1）ymlからコンテナ起動
`$docker-compose up -d --build`

（2）コンテナの中に入る（alpineの箇所はservice名に応じて変更する）
`$docker-compose exec alpine /bin/sh`


## ファイルの中身解説あり
```docker:Dockerfile
#dockerhubのalpineのimageを指定
FROM alpine:3.16.2@sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870

#docker内部のコマンド実行場所の指定
#今回はappディレクトリがないので、appディレクトリの作成も同時に行われる
WORKDIR /app
```

```yml:docker-compose.yml
#docker-composeのファイルバージョンを指定
#ここでは「3」でバージョン3を指定している
version: '3'

services:
  #service名を指定
  #ここでは「alpine」と指定している
  alpine:
    #実行時に常に再起動するように指定
    #ここでは「always」で常に再起動を指定している
    restart: always
    #立ち上げの設定を指定
    build:
      #dockerfileの参照先を指定
      #ここでは「.」でカレントディレクトリを指定している
      context: .
      #使用するdockerfile名を指定
      #ここでは「Dockerfile」と指定している
      dockerfile: Dockerfile
    #標準入出力(ターミナル？）をコンテナと結びつける設定
    #ここでは「true」で結びつけている？
    stdin_open: true
    #キーボード入力をコンテナが受け付けるようにする設定
    #ここでは「true」で結びつけている？
    tty: true
    #dockerfileがあるカレントディレクトリとコンテナ内部のディレクトリをマウントする設定
    #ホスト側:コンテナ側　の順番で記載する
    #ここでは、ホスト側「.」でカレント：コンテナ側「/app」でappディレクトリとマウントしている
    volumes:
      - .:/app
```

## 参考資料
https://charlie1012.hatenablog.jp/entry/2021/01/14/090000

https://prograshi.com/platform/docker/docker-image-tags-difference/

https://wa3.i-3-i.info/word12473.html

## 個人ブログ

https://takuma-tech.com/2022/09/28/289/
AWS Transit Gatewayとは？

## トランジットVIF利用時の注意点
directconnect 1/2/5/10 Gbps接続でのみ作成可能。パートナーによって共有型の接続では利用できない場合がある。


「共有型、専有型」と二つの定義があり、専有型に分類されていても対応できないことがあります。なのでサービス名称で判断せずに技術窓口に問い合わせをして確認しておくこと。

多くのパートナーが提供するレイヤー３網には利用可能な経路数の上限があります。AWSサービスのクォータに加えて、パートナー網の仕様を把握し全体設計をする。

パートナーが提供するTGW（トランジットゲートウェイ）に対する接続ではお客様の通信要件と合致しているか確認をする必要がある。

## AWS Transit Gatewayの特徴
数千のVPC、VPN,ダイレクトコネクトを接続可能である。複数のドメインを置くことができるので複雑なルーティングをすることができる。

以前のネットワークだとVPCやダイレクトコネクトだったり、かなり輻輳したネットワークの設計になっていた。


これを解決するためにTransitgatewayは、たくさんのVPCやダイレクトコネクト、VPNの中間役となってくれている。

小さいルーティング機能をまとめる、でかいルーターみたいなものである。
ルーティングハブを噛ませることでシンプルにルーティングのアーキテクチャにすることができる。

プロキシなしにいろんなネットワークサービスにアクセスすることができ、外部の多くのルーティングネットワークを一つに集約させることができる。


リージョンや本社ネットワーク、オンプレミス環境をつなげることも可能である。
全てネットワークを一箇所で集中管理することができるので便利である。

## ユースケースとして例えば・・
・複数のルートテーブルを使って柔軟なルート設計が可能である。

・デフォルトのルートをひとつのルートに設定することでオンプレミスと複数のVPCの接続を集約可能。一つのファイヤーウォールで管理して複数の宛先にトラフィックを飛ばすことも可能。

・オンプレミスとDXGWとの物理接続から複数のアカウントを接続することが可能である。
　※川のように複数の枝となる川から本流へ合流するといったイメージ。
【Heroku】本番環境へのデプロイ方法

どうもtaku3ukatです。
RailsチュートリアルでHerokuを初めて触ったので、備忘録として残します。
Herokuインストールについては割愛です。

## Herokuの本番環境にデプロイする流れ

### 概要
1. Gemfileで使用するgemのインストール
↓
2. git commit & push
↓
3. Herokuにログイン
↓
4. 本番環境をHeroku上に作成
↓
5. Herokuにプッシュ

### 1. Gemfileで使用するgemのインストール
開発環境、テスト環境、本番環境などの環境間でインストールするgemに差異がある場合指定する必要があります。
```ruby:Gemfile
group :development do
    #development環境にインストールするgemを記載   
end

group :test do
    #test環境にインストールするgemを記載
end

group :production do
    #production環境にインストールするgemを記載
    #以下例
    gem 'pg', '1.1.4'
end
```
上記記載の上、bundleコマンドでインストールしていきます。

### 2. git commit & push
参照：[Gitまとめ【備忘録】](https://qiita.com/taku3ukat/items/032d0c8819f85800eff5)

### 3. Herokuにログイン
```
$ heroku login --interactive
```
Heroku登録時のメルアドとパスワードを入力する。

### 4. 本番環境をHeroku上に作成
```
$ heroku create
```
ターミナル上に本番環境用URLが表示され、ブラウザからアクセス可能。
#### 本番環境のURLを忘れたら
```
$ heroku domains
```
で確認できる。

### 5. Herokuにプッシュ
```
$ heroku push heroku master(main)
```
Railsチュートリアルの2章では触れていませんが、GitとHerokuを連携させることで、Gitにプッシュされたコードは自動で本番環境にデプロイさせることもできるようです。

#### DBのマイグレーション(必要であれば)
環境ごと（開発、本番、テストなど）にDBが違う場合、それぞれマイグレーションする必要があるようです。
```
$ heroku run rails db:migrate
```


## その他Herokuコマンド
### ログ
```
$ heroku logs         # 直近イベントの表示
$ heroku logs --tail  # イベント発生毎に自動表示する
```
基本情報技術者試験_CPUの動作原理

CPUの動作原理
レジスタ
→レジスタは、CPUに内蔵されている高速な記憶装置です。レジスタには、次のようなものがあり、命令の実行時に使用します。
命令レジスタ：実行命令を格納する。
命令アドレスジスタ(プログラムカウンタ)：次に実行する命令のアドレスを格納する。
指標レジスタ(インデックスレジスタ)：基準となるアドレスを格納する。指標アドレス指定方法で使用する。
基底レジスタ(ペースレジスタ)：基準となるアドレスを格納する。規定アドレス指定方法で使用する。
アキュムレータ(累算器)：演算対象や演算結果を格納する。
汎用レジスタ：演算対象や演算結果を格納する。そのほか各種の目的に使用する。

命令語
→プログラムは、コンピュータに行わせる命令が集まったものです。プログラム言語で技術あれた命令は、最終的にコンピュータが理解できる１と０の機械語(命令語)に変換され、解読・実行されます。
機械語の命令語は、命令部とアドレス部(オペランド部)で構成され、命令によっては、アドレス部がないものや、アドレス部が複数あるものもあります。

命令実行サイクル
コンピュータが一つの命令を実行するとき、次の①から⑥までのような段階(ステージ)で進んで行きます。
命令アドレスレジスタ(プログラムカウンタ)には、これから実行する命令が格納されている主記憶のアドレスが保持されています。
①命令の取り出し：命令アドレスレジスタ(プログラムあカウンタ)を参照して、命令が格納されている主記憶上のアドレスを取得する。取得したアドレスから命令を取り出し(命令フェッチ)、命令レジスタに格納する。この時、命令アドレスレジスタには、次の命令のアドレスをセットする。
②命令の解読：命令レジスタの命令部は、デコーダ(解読器)で解読され、演算装置に表示を出す。
③実効あどれす計算：命令レジスタのアドレス部の値は、アドレスレジスタに送られ、処理対象のデータが格納されているアドレス(実効アドレス)を計算する。
④オペランドの取り出し：処理対象のデータを取り出し、演算装置に送る。
⑤命令実行：演算装置で演算を実行する。
⑥演算結果の格納：演算結果を格納する。
まとめたら、命令実行サイクルは命令の取り出し→命令の解読→実効アドレス計算→オペランドの取り出し→命令の実行→演算結果の格納となります。

アドレス指定方法
コンピュータは、主記憶上にあるプログラムの命令を一つずつ取り出して、解読・実行しています。
アドレス指定方法は、命令のアドレス部の値から処理対象のデータが格納されている実効アドレス(有効アドレス)を求める
方法です。アドレス修飾とも呼ばれています。

即値アドレス指定方法
即値アドレス指定方法は、命令のアドレス部にデータそのものを格納している方法です。

直接アドレス指定方法
直接アドレス指定方法は、命令のアドレス部の値を、実効アドレスとする方法です。

間接アドレス指定方法
間接アドレス指定方法は、命令のアドレス部の値が示すアドレスに格納されている値を、実効アドレスとする方法です。

相対アドレス指定方法
相対アドレス指定方法は、命令のアドレス部の値と指標レジスタの値の和を実効アドレスとする方法です。

指標アドレス指定方法
指標アドレス指定方法は、命令のアドレス部の値と指標レジスタの値の和を、実効アドレスとする方法です。
インデックスアドレス指定方法とも呼ばれています。

基底アドレス指定方法
基底アドレス指定方法は、命令のアドレス部の値と規定レジスタの値の和を、実効アドレスとする方法です。
ベースアドレス指定方法とも呼ばれています。

まとめると
即値：命令のアドレス部の値はデータそのもの
直接：アドレス部の値→実効アドレス
間接：アドレス部の値が示すアドレスに格納されている値→実効アドレス
相対：アドレスの値+プログラムカウンタの値→実効アドレス
指標：アドレス部の値+指標レジスタの値→実効アドレス
基底：アドレス部の値+基底レジスタの値→実効アドレス
AWS Direct Connect ゲートウェイとは

## オンプレミスとAWS VPCを接続するもの
ひとつのVIFを用いたプライベート接続で世界の全リージョンの複数のVPCと閉域で通信することができる。

追加の費用は不要であり無料で利用することができる。ロケーションと同一リージョンへの通信の遅延などは心配はありません。

複数のデータセンターをDXGWに接続することはできるがDXGWを経由して他のデータセンターへ繋ぐことはできない。
※日本拠点DRMC→DXGW→シンガポール拠点DC
×これはできないよ。

## Direct Connectのパートナー経由のタイプ
パートナの提供サービスは（占有型・共有型）の二つがあります。

・占有型
connectionはお客様へお渡しするもの、その中で自由でVIFを設定することができます。
物理帯域は1G,10Gを占有しているのでVIFはシェアする形になります。
帯域制御が必要な場合はそれは顧客側の機器で実現する。

・共有型
connectionはパートナーが所有している。パートナーの機能拡張で、帯域保証型でベストエフォートが様々である。

またAWSが認可しているパートナー制度もあり、それがDirect Connect サービスデリバリープログラム（SDP）である。サービスデリバリーパートナーはAWSの技術面の審査を受けて大容量のホスト接続をすることが可能である。

これによりサービスの利用者がより豊富なメニューから要件にあった帯域を選択することができ、ホスト接続をお客様アカウントで保持してVIFを作る権限が委譲されて運用に柔軟性が増す。
Bitbakeをpythonから使おう

# はじめに
yoctoを使ってカスタムしたlinuxをビルドをビルドする仕事してます。   
(僕は最近全然仕事してないけど)   
この仕事では、例えば以下のようなリクエストが来ます。  

* 特定のbbclass(core-image.bbclassとか)を継承したファイルをリストアップしてほしい
* すべてのパッケージのある変数(例えばPE,PV,PR)をリストアップしてほしい
* 特定のパッケージ(例えばgcc)にあたってるbbappendファイルをリストアップしてほしい

面倒くさくない？ 僕はgrepしたくないし、時間かかるからビルドもしたくないんだよ...  


# Bitbakeをpythonから使おう

面倒臭いので、なんとかする方法を調査しましょう。  
まず、bitbakeコマンドによるビルドの仕組みがざっくりこんな感じ。  

![bitbake.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185272/a6ed90f5-051a-2bde-6001-b80a3c34316f.png)

このTinfoilがすごい複雑なので使いづらいんですね。実際のコードは[ここ](https://git.yoctoproject.org/poky/tree/bitbake/lib/bb/tinfoil.py?h=kirkstone)  
一方、server_client間のIFは[ここ](https://git.yoctoproject.org/poky/tree/bitbake/lib/bb/command.py?h=kirkstone)にある程度きれいに定義されています。　　
これらの事情を考慮すると、↓のようにすればよさそうですね
  
![bitbake.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185272/cac48d75-0429-14b8-5fbd-33d454b669e5.png)

このbbclientをpythonで作ればlanguage serverとかからも使いやすくて良さそう。  

### 作ったもの

上述の経緯で作ったのが↓のbbclientです。

https://pypi.org/project/bbclient/

ドキュメントも用意しました。英語で書いてるので変なところあったら教えてほしいです...  

* [IFの仕様](https://angrymane.github.io/bbclient/bbclient.html)
* [使い方](https://angrymane.github.io/bbclient/usecase.html)

### 何ができるのか
IFが沢山あるので、全部は紹介できないんですが、とりあえず記事の冒頭で述べたユースケースを実装してみます。
まずはbbclientのインスタンスの初期化の方法を↓に示します。

```
import bbclient

# bbclientのインスタンスを初期化
project_path: str = "/PATH/TO/POKY"
init_command: str = ". oe-init-build-env"
client: BBClient = BBClient(project_path, init_command)

# サーバを立ち上げて接続
server_adder: str = "localhost" # 今はまだlocalhostしかサポートできてないです
server_port: int = 8081
client.start_server(server_adder, server_port)

# サーバからのイベントを全部受けとるように設定
ui_handler: int = client.get_uihandler_num()
client.set_event_mask(ui_handler, logging.DEBUG, {}, ["*"])

# レシピをパースしてキャッシュを生成する
ret = client.parse_files()
client.wait_done_async()
```

このclientを使ってそれぞれ以下のようにユースケースを実装できます  

> 特定のbbclass(core-image.bbclassとか)を継承しているレシピファイルをリストアップしてほしい

```
ret: List[GetRecipeInheritsResult] = client.get_recipe_inherits()
recipes_inherit = [i for i in ret if "/PATH/TO/core-image.bbclass" in i.inherit_file_paths]
for i in recipes_inherit:
    print(i.recipe_file_path)
```

> すべてのパッケージのある変数(例えばPE,PV,PR)をリストアップしてほしい

```
ret: List[GetRecipesResult] = client.get_recipes()
for i in ret:
    data_store_index: int = client.parse_recipe_file(i.recipe_files)
    pe: Any = client.data_store_connector_cmd(data_store_index, "getVar", "PE")
    pv: Any = client.data_store_connector_cmd(data_store_index, "getVar", "PE")
    pr: Any = client.data_store_connector_cmd(data_store_index, "getVar", "PE")
    print(pe, pv, pr)
```

> 特定のパッケージ(例えばgcc)にあたってるbbappendファイルをリストアップしてほしい

```
ret: List[str] = client.find_best_provider("gcc")
target_recipe_file_path: str = ret[3]
ret: List[str] = client.get_file_appends(target_recipe_file_path)
print(ret)
```

他にもこのclientからイメージをビルドしたり、依存関係のtaskdependsファイルを生成したりできます。  

# 最後に
よかったら使ってね。