OmniAICreator/Qiita-1.07M huggingface dataset:
【生成AIパスポート】試験学習 復習の自動化動画 その1 | ノーフリーランチ定理と、ハンターハンターの念能力の系統図が似ていると感じた話【動画 16分50秒】【YouTubeチャンネルからの転記です】

この記事は、わたしの[YouTubeチャンネル](https://bit.ly/Yamanaka-YouTube "Living without things. 持たない生き方 手放す生き方")にある公開動画を転記しております。
( どこかのタイミングで、プログラミング-Google Apps Script or iPaaS-Zapier をつかって自動転記させる予定です )

転記のための時間コストを少なくしたいので、文字装飾( Markdown記法 )を極力つかわずに書いております。

こちらが動画内容です👇

***

![99 サムネイル 【生成AIパスポート】試験学習 復習の自動化動画 その1 _ ノーフリーランチ定理と、ハンターハンターの念能力の系統図が似ていると感じた話【動画 16分50秒】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386308/b8747222-0d57-066e-f32b-3408796ca727.png)



* # 動画URL
    * https://youtu.be/mktsOqz0uy4

<br>

* # 動画タイトル
    * 【生成AIパスポート】試験学習 復習の自動化動画 その1 | ノーフリーランチ定理と、ハンターハンターの念能力の系統図が似ていると感じた話【動画 16分50秒】

<br>

* # 動画の説明欄(一部を抜粋)

📅撮影日 = 2023-10-14(土)

ひょんなことから生成AIパスポート試験を受けることになったので、手抜きしながら、学んだことの定着(記憶の定着)をねらっていきます。

・生成AIパスポートとは？
　https://bit.ly/WhatIs-GenerateAIPassport

やり方はこんな感じです。

・初回のインプット( 座学、教材学習、ChatGPT PlusやGoogle Bardへ質問する )

・アウトプット( 学んだことを声に出す → YouTube動画化 )

・2回目以降のインプット( 自分でつくった動画をながら聴きする )
　└朝起きてすぐ( YouTube + Chromecast )

　└ジョギング中( YouTube + スマホ )

などのやり方で繰り返しながら学習します。
技能を上げるには繰り返しが大切です。
初回のインプットではとにかく集中して、2回目以降のインプットでは繰り返し学習のためにとにかく手抜きします。

動画編集をしている時に、繰り返し学習ができる点も、楽ちんだなと感じています。


---


⏳開始時間
　00:00 イントロ
　00:24 本編開始

　00:51 「生成 AI パスポート試験 - 四股択一式 - 例題 3 問」から https://guga.or.jp/assets/sample.pdf
　　└ 00:58 「教師なし学習」と「強化学習」の違いとは？
　　　└ 教師なし学習は「似ているものをグループにする」学習
　　　└ 強化学習は「試行錯誤して最良の行動を学ぶ」学習

　　└ 06:22 ディープフェイク技術とは？
　　　└ ディープフェイク技術自体は道具の1つです。
　　　└ ディープフェイク技術をどのように使用するか、そしてその使用方法が他者に対して正直で公正であるかどうかが、良い使い方か悪い使い方かを決めるポイントです。

　　└ 08:11 ディープフェイクにつかわれる技術とは？
　　　└ 08:17 GAN( ガン ) - Generative Adversarial Network
　　　└ 09:51 VAE( ヴィーエーイー ) - Variational AutoEncoder

　11:53 「生成AIパスポート公式テキスト」( Kindle版 )から https://bit.ly/GenAIPass-Text
　　└ 12:05 半教師あり学習とは？
　　　└ 少量のラベル付きデータ( 教師データ、教師あり )と、大量のラベルなしデータ( 教師なし )を組み合わせて学習させる方法です。

　　└ 14:27 ノーフリーランチ定理とは？
　　　└ ある問題にとても良く働くアルゴリズムがあっても、それが他のすべての問題にも最適とは限らないということです。

　　　└ 15:36 ノーフリーランチ定理と、ハンターハンターの念能力の系統図が似ていると感じた話


---


✓ 🎥My videos are strongly related to this video. | この動画と関連が強い私の動画 ↙
　・“生成AIパスポート 試験学習(動画公開日で降順)”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMuGz8uBLRl1XyLqeRCIY11


　・“生成AIパスポート 試験学習(動画公開日で昇順)”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghOQB8T6uppVO_juFi-4xL3E


　・“山中一司がお金を払って買った情報”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghOW4Cnbj6lnltyToJae_Rb5


　・“自己投資”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghP1Gxpymfr6fVF9pRYuGt1P


　・“効果的にマインドマップを活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMTIuF-n2Uyaw6cqEMFt0aL


　・“マインドマイスター( クラウド型マインドマップ )を活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMCeUohu19ZbUilmcZnEJ1q


　・“マインドマイスター( クラウド型マインドマップ )でのプレゼンテーションの例”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMXJCYhmWK4bjAUG1uy78li


　・“効果的にChatGPTを活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghPfo1c-qmO2ERD7ldSgmblR


✓ 🎥Shortened URL for this video | この動画の短縮URL ↙
　https://bit.ly/3PXaVtb
BeautifulSoupでスクレイピングするときに文字化けする問題の対処

## はじめに
スクレイピングをするときにどうしても文字化けしてしまう大変さ...
なんとか解決できたので記録しておく

## エラー対処
コードとしてはwebサイトからBeautifulSoupで文字を取得してきてcsvに書き込むというもの
文字化けはcsvに書き込むときではなく読み込んだ段階で起きていた。

以下コードの抜粋
```python
from bs4 import BeautifulSoup
import requests
import csv
import textwrap
import re


#urlの指定
url = input("csvファイルに書き出したいサイトのURLを入力してください:")


#urlからwebページを取得
r = requests.get(url)
# print(r.content)
r.encoding = r.apparent_encoding

#webページを分析
soup = BeautifulSoup(r.content, 'html.parser')

t = str(soup.article.header.h1.a.string)
print(t)
```
printの結果文字化け...

chardetをimportしてサイトの文字コードを調べるとutf-8とのこと。

原因は`soup = Beautiful...`のところっぽいので調べてみて、見つけた対処法をやってみると治った

改善後のコードは以下の通り
```python
from bs4 import BeautifulSoup
import requests
import csv
import textwrap
import re


#urlの指定
url = input("csvファイルに書き出したいサイトのURLを入力してください:")


#urlからwebページを取得
r = requests.get(url)
# print(r.content)
r.encoding = r.apparent_encoding

#webページを分析
soup = BeautifulSoup(r.content, 'html.parser')
soup = BeautifulSoup(r.content.decode("utf-8", "ignore"), "html.parser") #追加

t = str(soup.article.header.h1.a.string)
print(t)
```
なぜか`r.encording`の文字コードではなく`soup`の方で違う文字コードが使われているみたい。`soup`の方でも文字コードを指定してやるとうまくいくようだ。
ただ指定するだけではエラーが出るようなので、エラーを無視するために`r.content.decode("utf-8", "ignore")`と書き足せばよい...みたい
その上の行は多分いらない。

## おわりに
`r.text`を`r.content`にすれば治るよ！ってサイトが多すぎて探すのに苦労しました...
なにがともあれ治ってよかった。
とりあえず言えることは日本語はクソということです。

## 参考サイト
https://virtualsanpo.blogspot.com/2020/01/pythonbeautifulsoup.html
js問題date

```HTML:date
<!DOCTYPE html>
<html>
<head>
    <title>Js問題 CalcDate</title>
</head>
<body>
    <input type="text" id="dateInput" placeholder="yyyy/MM/dd">
    <br>
    <button onclick="CalcDate()">計算</button>
    <br>
    <input type="text" id="result">
    
    <script>
        function CalcDate() {
            
            //入力された日付の処理
            let inputStr = document.getElementById("dateInput").value;
            let inputDate = new Date(inputStr);
            let num1 = inputDate.getFullYear() + inputDate.getMonth() + 1 + inputDate.getDate();
            console.log(num1);
            //本日日付の処理
            let today = new Date();
            let num2 = today.getFullYear() + today.getMonth() + 1 + today.getDate();
            console.log(num2);
            // 結果を表示
            document.getElementById("result").value = num1 - num2;
        }
    </script>
</body>
</html>

```
js問題bmi

```html:bmi

<!DOCTYPE html>
<html>
<head>
    <title>Js問題 CalcBmi</title>
</head>
<body>
    <input type="text" id="weight" placeholder="体重 (kg)" oninput="InputJuge(this)">
    <input type="text" id="height" placeholder="身長 (cm)" oninput="InputJuge(this)">
    <button onclick="calcBmi()">計算</button>
    <br>
    <input type="text" id="result" placeholder="BMI" readonly>

    <script>
        function InputJuge(elementId) {
            
            if (!/^[0-9]+$/.test(elementId.value)) {
                elementId.value = elementId.value.replace(/[^0-9.]/g, '');
                alert("半角数字を入力してください.");
            }
        }

        function calcBmi() {
            const weightValue = document.getElementById("weight").value;
            const heightValue = document.getElementById("height").value;

            const weight = parseFloat(weightValue);
            const height = parseFloat(heightValue) / 100;
            const bmi = weight / (height * height);
            document.getElementById("result").value = bmi.toFixed(2);
        }
    </script>
</body>
</html>

```
AivenがOpenSearch® 2を発表！

<font color="Grey">*[Aiven introduces OpenSearch® 2!](https://aiven.io/blog/aiven-introduces-opensearch-2)の翻訳です。*</font>

2022年10月6日

# Aiven、OpenSearch® 2を発表！

AivenはOpenSearch® 2をマネージドサービスとして提供します。AivenのOpenSearch® 2の導入方法と主な改善点についてご紹介します。

[OpenSearch](https://aiven.io/blog/introduction-to-opensearch)は、昨年の発表以来初のメジャーバージョンアップを行い、豊富な新機能とパフォーマンスの向上を実現しました。この[完全オープンソースのElasticSearchフォーク](https://aiven.io/blog/migrate-elasticsearch-client-to-opensearch)は、そのさらなる開発に専念する強力なコミュニティに支えられており、もちろんAivenもそのコミュニティの熱心な一員です。


新バージョンで何ができるのか？


## OpenSearch 2 のハイライト


### Lucene 9.1 によるパフォーマンスの向上


OpenSearch には Apache Lucene の最新バージョンが搭載され、パフォーマンスが向上し、I/O の高速化とインデックスの高速化が実現しました。


### ドキュメントレベルアラート


OpenSearch 2 では、ドキュメントレベルでアラートを監視、生成することができます。さらに、OpenSearch 2 は通知プラグインを導入し、個々のプラグインで手動でアラートを設定する代わりに、OpenSearch のすべての通知を一元化します。


### MLコモンズのアップグレード


OpenSearchは、追加のワークロードに対応するために、以前のML Commons Pluginのアップグレードを提供します。この新しいバージョンでは、OpenSearch は ML モデルの開発を簡素化するために、従来の K-means と RCF に加えて、線形回帰と局在化のための新しいアルゴリズムを導入しています。


### すでにAiven for OpenSearch 1をお使いですか？


すでにAiven for OpenSearch 1をご利用で、これらの新機能やパフォーマンス向上の恩恵を受けたい場合は、お好きなようにアップグレードしていただけます。Aivenは当面OpenSearch 1のサポートを継続し、現在のバージョンからAiven for OpenSearch 2への安全なアップグレードパスを提供しています。



> ![](/build/_assets/shape-quote-WGSAHX4E.svg)
> OpenSearch バージョン 2 では、すべての API エンドポイントからマッピングタイプのパラメータが削除され、インデックスがドキュメントタイプごとに分類されるようになりました。詳細は[こちら](https://github.com/opensearch-project/opensearch/issues/1940)をご覧ください。
>
>
>


--


その他、ご意見・ご質問等ございましたら、[Twitter](https://twitter.com/aiven_io)または[LinkedIn](https://www.linkedin.com/company/aiven/)までご連絡ください。[ブログ](https://aiven.io/blog)のRSSフィードをフォローし、[ドキュメント](https://docs.aiven.io/)をご覧ください。また、Aivenと私たちのサービスに関する最新ニュース、さらにオープンソース全般に関する情報をご希望の方は、[月刊ニュースレターを購読](https://aiven.io/newsletter)してください！
Rubyでself.includedをしたときの挙動について

# はじめに

実装をしているときに`Klass`という言葉がでてきました
それをきっかけに`include`周りで何をしているのかというところを理解したので軽くまとめていきます

# 問題

以下のようなコードがありました

```rb:sample_controller.rb
class Companies::SampleController < ApplicationController
  include Mixins::TestController
```

```rb:mixins/test_controller.rb
module Mixins::TestController
  module InstanceMethods
    def load_example


(省略)

  def self.included klass
    klass.send :include, InstanceMethods

    method_name = case klass.name
      when 'HogeContRoller' then :load_hoge
      when 'FugaController' then :load_fuga
      else :load_other
      end
    klass.before_filter method_name
  end
end
```

ここで`sample_controller`が`Mixins::TestController`を読み込んでいるのはわかったのですが、そこで

```rb
def self.included klass
```

というのをやっておりそこからよくわからなくなりました

# 解決方法

`def self.included`をすると、`include`が`sample_controller.rb`で呼ばれた段階で、発火するようになります

そして`klass`というのをがありますが、これは単に変数名で`class`というのが予約後なために使っているものでした

`klass`には`include`したコントローラーの情報が渡ってくるため、`klass.name`でコントローラー名で処理を変えることができます(whenの部分)

```rb
lass.send :include, InstanceMethods
```

この部分ですが、`InstanceMethods`は上に書いてある

```rb
  module InstanceMethods
    def load_example
```

この部分を表しており、このモジュールをさらに`include`するようにしています。

`klass.send`としているのはプロテクトがされているためそれを突破するためにsendを利用して親である`sample_controller`で`InstanceMethods`を利用できるようにしていています(includeできるようにしています)

最後に

```rb
klass.before_filter method_name
```

をすることでコントローラーごとに`before_filter`するものを設定して、`include`するだけで自動的に`before_filter`が行われるようになります

# おわりに

なぜかコントローラーで`before_filter`していないのにインスタンスが使えるよいうになっていて不思議に思いましたが、このようなからくりがありました

Ruby自体の仕組みを勉強することがなかったのですが、とても面白いなと感じました
zshの補完で候補をインクリメンタルに絞り込む

ここまではみんなやっていると思う。メニュー補完を有効にする設定だ。
```zsh
autoload -Uz compinit && compinit -u
zstyle ':completion:*' menu select
```

次のように書くと、候補をインクリメンタルサーチで絞り込める（前方一致）。

```zsh
zstyle ':completion:*' menu select interactive
```

あるいは次のように書くと、候補をインクリメンタルサーチで絞り込める（部分一致）。ただし候補を選択確定するのにEnterを2回押さなければならなくなる。

```
zstyle ':completion:*' menu select search
```

Tabを押した直後は通常のメニュー補完で、特定のキーを押したときだけ絞り込みモードに移行することもできる:
```zsh
zstyle ':completion:*' menu select
bindkey -M menuselect '^K' vi-insert                           # 前方一致で絞り込み
bindkey -M menuselect '^L' history-incremental-search-forward  # 部分一致でインクリメンタルサーチ（not 絞り込み）
```

他にもメニュー補完中のキーバインドは`bindkey -M menuselect`でカスタマイズ可能だ。

```
accept-line - Validate the selection and leave the menu.
send-break - Leaves the menu selection and restore the previous command.
clear-screen - Clear the screen without leaving the menu selection.
accept-and-hold - Insert the match in your command and let the completion menu open to insert another match.
accept-and-infer-next-history - Insert the match and, in case of directories, open completion menu to complete its children.
undo - Undo.
vi-forward-blank-word - Move cursor to next group of match.
vi-backward-blank-word - Move cursor to previous group of match.
beginning-of-buffer-or-history - Move the cursor to the leftmost column.
end-of-buffer-or-history - Move the cursor to the rightmost column.
vi-insert - Toggle between normal and interactive mode. We’ve seen the interactive mode above.
history-incremental-search-forward and history-incremental-search-backward - Begin incremental search.
```

特に下記2個は設定しておくとたまに便利かもしれない。
```zsh
bindkey -M menuselect '^O' accept-and-hold                # 選択してメニューを維持（複数選択する場合に便利）
bindkey -M menuselect '^J' accept-and-infer-next-history  # 候補を選択し、再度補完を起動する（パスの続きを入力する際に便利）
```

参考：

https://thevaluable.dev/zsh-completion-guide-examples/

これらのstyleの公式なドキュメントは[Standard Styles](https://zsh.sourceforge.io/Doc/Release/Completion-System.html#Standard-Styles
)の`menu`のところにある。

こういうチマチマした設定をせずにzshを便利にしたい人には[zsh4humans](https://github.com/romkatv/zsh4humans)がいいかもしれない。powerlevel10k作者のromkatv氏による「設定無しで欲しい機能が全部揃っている」zshフレームワークで、fzfによる補完候補絞り込み機能がある。romkatv氏のことだから、速度にも最大限に注意を払っていると思われる。
MapKit for SwiftUI の scope の使いどころ


## 前説

iOS17から、MapKitがSwiftUIで定義することができます。

単純にマップを表示する場合は、以下のコードで表示できます。

```swift
import SwiftUI
import MapKit

struct ContentView: View {
    
    // MARK: - State
    
    // MARK: - Properties
    
    // MARK: - View
    var body: some View {
        VStack {
            Map()
        }
    }
}

```

地図を表示するだけならこれでいいのですが、 [公式ドキュメント](https://developer.apple.com/documentation/mapkit/map) を見ていると `scope` を初期化時に指定することができます。この `scope` は、Namespaece.IDを指定して、デフォルトは `nil` です。

なんとなくMapに名前空間を与えている印象はありますが、この `scope` はどのように活用できるのでしょうか？

## MapContorol における scope の活用

MapContorolは、例えば、ユーザーの現在地に地図を移動するボタンや、地図が向いている方向を示すコンパスアイコンのことです。これらを **地図とは違う場所に表示** したい場合に `scope` を活用します。

以下は、サンプルコードです。

```swift
struct ContentView: View {
    
    // MARK: - State
    @Namespace var namespace
    
    // MARK: - Properties
    
    // MARK: - View
    var body: some View {
        VStack {
            Map(scope: namespace)
            
            HStack {
                // コンパス
                MapCompass(scope: namespace)
                
                // ピッチトグル
                MapPitchToggle(scope: namespace)
                
                // 地図のスケール表示
                MapScaleView(scope: namespace)
                
                // 現在位置に移動させるボタン
                MapUserLocationButton(scope: namespace)
            }
        }
        .mapScope(namespace) // これを忘れずに記載
    }
}

```

Stateとして `@Namespace` を宣言しておきます。そして、Mapを初期化する際に `namespace` を `scope` の引数として渡します。

VStack の中に、コンパス、ピッチトグル、地図のスケール（縮尺）表示、現在地に移動させるボタンを HStack で宣言します。これらは、ぞれぞれ地図の外に表示されることになります（後述のデモを参照）。また、それぞれの構造体に、先程宣言した `namespace` を `scope` の引数として渡します。

そして、VStackに、mapScopeモディファイアを宣言して `namespace` を渡します。

これをすることで、地図の動きに合わせて　**地図外にコンパスを表示** したり、 **地図外にある現在地ボタンを押してユーザーの現在位置に地図を移動** したりすることができます。

## デモ

実際に動かすと以下のようになります(現在地ボタンは、アプリ側で位置情報の許可が有効になっていないと動作しません)。

![mapkit-swiftui-scope-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93706/6cc1bc89-d10f-af19-dd5a-5d1da57cc406.gif)

## 補足

純粋に地図の上に位置情報ボタンなどを表示したい場合は、 `scope` を使用せず以下のように宣言します。

```swift
import SwiftUI
import MapKit

struct ContentView: View {
    
    // MARK: - State
    
    // MARK: - Properties
    
    // MARK: - View
    var body: some View {
        VStack {
            Map()
                .mapControls {
                    MapUserLocationButton()
                }
        }
    }
}

```

![プレビュー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93706/95fcb034-a464-3868-77d8-5234e45042af.png)
javaのentityクラス、modelクラス、dtoクラスの使い分け

# entityクラス

- DBのテーブルから取得した1レコード
- SQLで加工をしていない生データ
- SELECT * FROM テーブル名 WHERE 何か条件;
で取れて来るデータ
(WHERE句は無くてもOK)

# modelクラス

- DBのテーブルから取得したデータ
- SQLで取得データを加工している
- SELECT SUM(カラム名) FROM テーブル名;
とか、
SELECT カラム1, カラム3, カラム5 FROM テーブル名;
みたいに、カラムを指定して取得されたデータ

# dtoクラス

- ただの入れ物
- 変数の塊みたいな
- 必ずしも「DBから取ってきたデータ」というわけではない
【Mac】コマンドラインでBluetoothを制御する(blueutil)

# はじめに
いつからか、MacにiOS同様のコントロールセンターが搭載され、
以前はメニューバーの右上にBluetooth用のアイコンからBluetoothの接続などをコントロールできたのがコントロールセンター経由となってしまった...

正直コントロールセンター使いにくい、、、

ということで、CLIでBluetoothの制御を考えることに。

## 環境
macOS:Ventura 13.3
プロセッサ：ARM
# Bluetutil
LinuxにはBluetoothctlというBluetooth用の制御ツールがあったりしますが、Macにも似たようなものはないのだろうか？

...

何やら[Blueutil](https://github.com/toy/blueutil/tree/main)というツールがMacOS向けの制御ツールとして提供されていた。

## インストール
Homebrewでインストール可能です。
```zsh:インストール
brew install blueutil
```

## Bluetoothの状態確認(参照系)

### 用語
| 用語 | 解説 |
| - | - |
| ID | MACアドレス |
| pair | ペアリング |
| connect | ペアリング済みデバイスに対するBluetooth接続

IDに当たる部分はリファレンス上では機器の名前でも問題ないようだが、自分の環境ではうまく認識されなかったため、無難にMACアドレスを用いるのが良い。

昨今ではBluetoothも一般的となったため、
ペアリングと接続で異なるニュアンスを持つことは認識ずみであると思うが、「ペアリング=接続」ではないことに注意。

### 状態コード
|  状態コード  |  説明  |
| :----: | :----: |
|  1  |  ON状態  |
|  0  |  OFF状態 |

### Bluetoothのon/off確認
```zsh:Bluetoothのon/off状態確認
blueutil -p
```
```zsh:結果
1
```

### 周辺のBluetoothデバイスをスキャンする
```zsh:機器のスキャン
blueutil --inquiry
```
なお自分の環境ではなぜかうまく検知できなかった

### ペアリング済みデバイスの確認
```zsh:ペアリング確認
blueutil --paired
```
```zsh:出力フォーマット
address: <MACアドレス>, <接続状態>, <お気に入り登録の有無>, <ペアリング状態>, name:<Bluetooth機器の名称>, recent access date:<最終アクセス日(接続日)>
```
### 接続済みデバイスの確認
```zsh:接続デバイス確認
blueutil --connected
```
出力はペアリング確認の際の出力フォーマットと同じ。

### デバイスの情報を参照する
```zsh:デバイス情報の参照
blueutil --info <ID>
```
出力フォーマットは上に同じ。

IDは機器のMACアドレスを指定する。
#### MACアドレスのフォーマット
MACアドレスは以下のフォーマットで記述可能
| フォーマット |
| - |
| xxxxxxxxxxxx |
| xx-xx-xx-xx-xx-xx |
| xx:xx:xx:xx:xx:xx |

尚、大文字/小文字の区別はしていない模様。

### 接続状態の確認
```zsh:接続確認
blueutil --is-connected <ID>
```
```zsh:出力
1
```
主にスクリプトなどの判定処理で用いると考えられる。

## Bluetoothの制御

### BluetoothをONにする。
```zsh:BluetoothのON
#短いオプション
blueutil -p 1

#長いオプション
blueutil --power 1
```
リファレンスの書きっぷり的には「状態をセットする」といったところ。
そのため、状態コードの値をオプションのパラメータとして渡す。

### BluetoothをOFFにする。
```zsh:BluetoothのOFF
#短いオプション
blueutil -p 0

#長いオプション
blueutil --power 0
```

### 接続する
```zsh:接続
blueutil --connect <ID>
```

### 接続解除する
```zsh:接続解除
blueutil --disconnect <ID>
```

### ペアリングする
```zsh:ペアリング
blueutil --pair [PIN]
```

### ペアリングを解除する
```zsh:アンペアリング
blueutil --unpair <ID>
```
## その他

### 出力フォーマットを変更する。
デフォルトではカンマ区切りで出力されるが、
formatオプションを用いることで、json形式で出力することも可能。

```zsh:json出力
blueutil --paired --format json 

#整形されたjsonフォーマットで出力
blueutil --paired --format json-pretty
```

### helpを表示する
```zsh:help
blueutil --help
```

# 余談
他にもオプションは存在するが、
一部オプションは用途不明なものが所々あった。
また一部Bluetooth機器※がリスト上に表示されないなどの問題も見られた。
※MX Keys mini

ただし、筆者の機器(Mac mini M2)はBluetoothの接続が周りがかなり不安定なため、固有の問題かもしれない。

# 参考
https://github.com/toy/blueutil/tree/main
プログラミング初心者が覚えたいLinuxの基礎コマンド【25選】

 
## 《フォルダ関連》
ディレクトリ(以下、dir)と呼ぶ

★今いる場所…カレントdir
★一番親のdir…ルートdir

### ① dir作成
```
mkdir dir名
```  
### ② 行きたい(cd)dirへ

```
cd dir名
※1層下まで
```
### ③ 今いる場所(カレントdir)
```
pwd
※ルートdirからカレントdirまでの階層が全て表示
```
### ④ dir内の中身(どんなファイルが入っているか)を1層まで調べることができる
```
ls
```

### ⑤ 1つ親のdirへ移動
```
cd ..
※..の前は半角スペース
```
### ⑥ ホームdir(作業する起点となるdir)へ移動
```
cd
```
## 《ファイル関連》

### ⑦ ファイル作成
```
touch ●●.txt
```
### ⑧ ファイルの中身を開く
```
cat ●●.txt
```

## 《dirやファイルの操作》

### ⑨ ファイルの移動
```
mv A B
A：移動させたいファイル名.拡張子
B：移動先のdir名
※Aをdir名にすることで、ファイルだけでなくdirも移動可能
```
### ⑩ ファイル名の変更
```
mv A B
A:現在のファイル名.拡張子又はdir名
B:newファイル名.拡張子又はdir名
※ファイル名はファイル名を、dir名はdir名を変更
```
### ⑪ ファイルのコピー
```
cp A B
A:コピーしたいファイル名.拡張子
B:新しいファイル名.拡張子
```
### ⑫ dirのコピー
```
cp -r A B  
A:コピーしたいdir名
B:新しいdir名
```
### ⑬ ファイル削除
```
rm 削除したいファイル名.拡張子
```
### ⑭ dir削除
```
rm -r 削除したいdir名
```
### ⑮ 中身が空のﾃﾞｨﾚｸﾄﾘを削除
```
rmdir ﾃﾞｨﾚｸﾄﾘ名
```
### ⑮ コマンドプロンプトの終了
```
Exit
```
### ⑯　スクロール形式でファイルの中身を表示
```
less ファイル名
```
### ⑰ ファイルの中身の末尾から数行を表示
```
tail ファイル名　　　　　　
※ -f オプションを使うことで、ログをリアルタイムに監視するtailコマンドを起動
(例：tail -f asuka.txt)
```
### ⑱ ln　ファイルのリンクを作成

※ハードリンクは実体が同じファイルで、シンボリックリンクは「愛称」みたいなもの。

::: note
#### A) ファイルのリンク（ハードリンクまたはシンボリックリンク）を作成　
```
ln [オプション] ファイル名 リンク名
※[]内は省略可能
```
#### B) ファイルのシンボリックリンクを作成
```
ln -s ファイル名 リンク名
```
#### C) ディレクトリのシンボリックリンクを作成
```
ln -s ディレクトリ名 リンク名
```
#### D 指定したディレクトリの中にシンボリックリンクを作成
```
ln -s ファイル1 ファイル2…… ディレクトリ
```
#### E バックアップファイルを作成
`-b`を付けると、リンク名と同名の既存ファイルがあった場合に「リンク名`~`」という名前で保存される
```
ln -sb asuka.txt nurse
※ln -sでは通常、既存ファイルと同名にすると上書きされてしまう。なので「-sb」を使う。
```
:::
### ⑲　ファイル検索
```
find 検索する場所  [オプション]  検索ファイル名
```
### ⑳ chmod
参照：分かりやすかった記事

https://qiita.com/shisama/items/5f4c4fa768642aad9e06

### ㉑ ファイル所有者の変更
```
chown ユーザー名 ファイル名
```
### ㉒ 実行中のプロセスを表示
```
ps
```
### ㉓ プロセスの終了
```
kill 終了したいプロセスID

(使い方)
　「tail -f ファイル名」でtailコマンドを起動したとする
　「ps aux」でプロセス一覧を表示し、例）tail -f asuka.txtコマンドに対するプロセスIDを調べる

```
## 《その他》
㉔ コマンドラインでは、過去に実行したコマンドを上矢印キー「↑」で入力することができる

㉕ ファイル名を入力するとき、ファイル名の途中まで入力し、`tabキー`を押すとファイル名を補完してくれる
remark-mathでCannot read properties of undefined (reading 'mathFlowInside') エラーが出るとき

# 結論
バージョンを下げる。
今回は4.0.0まで下げたらうまくいった
```
npm install remark-math@4.0.0
```

# 背景情報
githubで公開されていた[こちらのブログテンプレート](https://github.com/sub-t/blog-template)数式表示に対応しておらず、自分でremark-mathを導入する必要があった。remarkのバージョンが古く、プラグインのバージョンもそれに合わせる必要があった

# 参考文献
[https://github.com/remarkjs/remark-math/issues/89](https://github.com/remarkjs/remark-math/issues/89)
[OCI]Always FreeのAutonomous Databaseを使用してOCI Functionsのファンクションを定期実行してみた

# はじめに

OCI FunctionsのファンクションをAutonomous DatabaseからSQLファンクションとして呼び出せるようになったので、Autonomous Databaseを使用してOCI Functionsのファンクションを定期実行させてみました。

# 1. OCI FunctionsのファンクションをSQLファンクションとして呼び出すための設定

こちらの記事を参考に、OCI FunctionsのファンクションをAutonomous DatabaseからPL/SQLファンクションとして実行できるように設定します。
（ここではobject_storage_file_zipというファンクションを対象にしています）

https://qiita.com/500InternalServerError/items/ac17dbd10ec887301dc5

# 2. OCI Functionsのファンクションを実行するPL/SQLプロシージャの作成
OCI Functionsのファンクションobject_storage_file_zipを実行するPL/SQLプロシージャEXECUTE_OCI_FUNCTIONを作成します。
```
SQL> CREATE OR REPLACE PROCEDURE EXECUTE_OCI_FUNCTION
     IS
       result CLOB;
     BEGIN
       SELECT object_storage_file_zip(
         '{
            "COMPARTMENT_ID": "ocid1.compartment.oc1..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "REGION": "ap-tokyo-1",
            "SOURCE_BUCKET": "SourceBucket",
            "SOURCE_FILES": "/",
            "TARGET_BUCKET": "TargetBucket",
            "ALLOW_OVERWRITE": "true"
         }' 
       ) as response INTO result
       FROM dual;
     END;
     /

Procedure EXECUTE_OCI_FUNCTION compiled

SQL>
```
# 3. OCI Functionsのファンクションを実行するPL/SQLプロシージャを定期実行するDBMS_SCHEDULERジョブの作成
作成したPL/SQLプロシージャEXECUTE_OCI_FUNCTIONを日本時間2023/10/25 0:20に初回実行し、その後10分間隔で定期実行するDBMS_SCHEDULERジョブEXECUTE_OCI_FUNCTION_JOBを作成します。
```
SQL> BEGIN
     DBMS_SCHEDULER.CREATE_JOB (
          job_name           =>  'EXECUTE_OCI_FUNCTION_JOB',
          job_type           =>  'STORED_PROCEDURE',
          job_action         =>  'ADMIN.EXECUTE_OCI_FUNCTION', 
          start_date         =>  TO_TIMESTAMP_TZ('2023-10-25 00:20:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM'),
          repeat_interval    =>  'FREQ=MINUTELY;INTERVAL=10',
          auto_drop          =>  FALSE,
          enabled            =>  TRUE,
          job_class          =>  'HIGH'
      );
     END;
     /

PL/SQL procedure successfully completed.

SQL> 
```

# 4. 動作確認
しばらく待ってからOCI Functionsのファンクションのログを確認してみます。

![スクリーンショット 2023-10-25 0.58.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/7bf23dab-c516-e0fb-7810-94c700fee0c1.png)

OCI Functionsのファンクションが2023/10/24 15:20:00 UTC（2023/10/25 0:20 JST）に初回実行され、その後10分間隔で定期実行されていることが確認できました。

以上で、Autonomous Databaseを使用してOCI Functionsのファンクションを定期実行することが可能なことが確認できました。

# 参考情報
・[DBMS_SCHEDULER.CREATE_JOBプロシージャ](https://docs.oracle.com/cd/F19136_01/arpls/DBMS_SCHEDULER.html#GUID-7E744D62-13F6-40E9-91F0-1569E6C38BBC)
CVPR2023の枝刈り論文 (2)

# 概要

この記事では、[CVPR2023](https://cvpr2023.thecvf.com/Conferences/2023/)の枝刈り論文を紹介します。[^1]
[その1](https://qiita.com/kyad/items/7aa5277cada9268a70e1)

[^1]: 画像や数式は論文から引用しています。


# Pruning Parameterization with Bi-level Optimization for Efficient Semantic Segmentation on the Edge

https://openaccess.thecvf.com/content/CVPR2023/papers/Yang_Pruning_Parameterization_With_Bi-Level_Optimization_for_Efficient_Semantic_Segmentation_on_CVPR_2023_paper.pdf

- 概要：エッジ向けセマセグViTの最適化。
- 新規性：TopFormerで枝刈りパラメータをbi-level optimizationで最適化する。


# Joint Token Pruning and Squeezing Towards More Aggressive Compression of Vision Transformers

https://openaccess.thecvf.com/content/CVPR2023/papers/Wei_Joint_Token_Pruning_and_Squeezing_Towards_More_Aggressive_Compression_of_CVPR_2023_paper.pdf

- 概要：TPS. Vision Transformer向け枝刈りの改善
- 研究機関：MEGVII
- 新規性：刈られたトークンの情報を有効活用する
- キモ：Fig2(c)の形にNNで似た特徴量にマッチングする。


# DepGraph: Towards Any Structural Pruning

https://openaccess.thecvf.com/content/CVPR2023/papers/Fang_DepGraph_Towards_Any_Structural_Pruning_CVPR_2023_paper.pdf

- 概要：Structured pruningでレイヤ間でチャンネル数の依存がある場合に対応する
- 研究機関：Huawei
- 新規性：(4)式でグループ単位で刈る
- キモ：グループのFig.1のような依存関係をdependency graphとして自動生成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/51cc864e-9447-f53c-fb97-37c3792d0d59.png)


# おまけ

## TopFormer: Token Pyramid Transformer for Mobile Semantic Segmentation (CVPR2022)

https://openaccess.thecvf.com/content/CVPR2022/papers/Zhang_TopFormer_Token_Pyramid_Transformer_for_Mobile_Semantic_Segmentation_CVPR_2022_paper.pdf

- 概要：セマセグ向けモバイル用ViT
- 新規性：Fig. 2
SSHで繋いだホストで.zshrcが読み込まれていない

# 問題
SSHコマンドを使って、リモートホストで直接コマンドを実行した場合、`.zshrc` が読み込まれていませんでした。

```zsh:.zshrc
PATH=/bin:$PATH
```

```bash
$ ssh example.com 'echo $PATH'

/usr/local/sbin:/usr/local/bin  # ここに/bin が無い
```

調べたところSSHで繋いだ場合には `login shell` と呼ばれる状態で起動しており、 `login shell` は `.zshrc` を読みに行きません。

# 調査方法

色々調べたところ `.zprofile` に書くと良い、というのを見ましたが、書き込んでも変化はありませんでした。

下記にかなり詳細な読み込み順序が書かれていました。

<img src="https://i.stack.imgur.com/17NoJ.png">

この図によるとSSHで繋がれたシェルは「login shell」かつ「non interactive shell」で黄色い線のように見えるのですが、ワンライナーの場合にはどうやら違うらしく、青い線のようです。

そこで `~/.zshenv` に書き込みました。


```zsh:.zshrc
PATH=/bin:$PATH
```

```bash
$ ssh example.com 'echo $PATH'

/bin:/usr/local/sbin:/usr/local/bin  # /bin が出てきた
```

なお `/etc/zprofile` のようなファイルが呼ばれるかどうかについてはインストール済みの環境で `man zsh` して FILES を確認すると良いとのことでした。
確認すると実際には `/etc/zprofile` ではなくもう一つ下の `/etc/zsh/zprofile`

下記はその例。

```bash
$ man zsh | grep -A20 FILES

FILES
       $ZDOTDIR/.zshenv
       $ZDOTDIR/.zprofile
       $ZDOTDIR/.zshrc
       $ZDOTDIR/.zlogin
       $ZDOTDIR/.zlogout
       ${TMPPREFIX}*   (default is /tmp/zsh*)
       /etc/zsh/zshenv
       /etc/zsh/zprofile
       /etc/zsh/zshrc
       /etc/zsh/zlogin
       /etc/zsh/zlogout    (installation-specific - /etc is the default)
```

# 解決方法

ということでSSHのワンライナーでも呼ばれる `~/.zshenv` に　`.zshrc` を呼ばれるように書いておきました。

```zsh:~/.zshenv
if [ -f ~/.zshrc ]; then
	. ~/.zshrc
fi
```

# 参考

https://unix.stackexchange.com/questions/38175/difference-between-login-shell-and-non-login-shell/46856#46856

https://unix.stackexchange.com/questions/537637/sshing-into-system-with-zsh-as-default-shell-doesnt-run-etc-profile

https://zenn.dev/ota42y/articles/41c40ddef10a59

https://qiita.com/noymer/items/8a21ec12be2de2892f1b
ポートフォリオ作成に向けて

# はじめに
ポートフォリオを作成します！これまでにも何度か作成をしたのですが、設計もちゃんとしてなかったので頓挫しまくりでした:frowning2:
今回はちゃんとした設計も行い、作成に向けてできるだけアウトプットしていこうと思います。
拙い点多々あると思いますがご容赦ください:bow_tone1:

# 作成するシステム
**■アイデア**
よく自炊をするのですが、買い出しに行く際食材や調味料などの在庫情報を確認し忘れることが多々あるので、在庫管理システム（家庭内ver.）のようなものを作成予定です！


**■機能**
　・ログイン、新規登録
　・在庫情報の登録（賞味、消費期限取れたら）
　・食材、調味料などをマスタとして登録
　・外部APIでレシピの取得
現時点ですが、この程度を考え中。

# 技術選定
これも現時点ですが、とりあえず今勉強中のReactは使用する予定です！
バックエンドは未定。。。
開発はgitで管理しながら進めていきます:punch:

# 最後に
また何かあれば更新します〜頑張ります:v:
CloudFront関数でBasic認証したらletsEncrypt自動更新できなくなった。

### [原因]SSL証明書の再発行リクエストがBasic認証で弾かれていた。

CloudFrontを実装した際に、Basic認証をCloudFront関数で行う様に変更した。
原因となったCloudFront関数の内容はこちら
```
var authUser = 'hogehoge';
var authPass = 'hogepassword';

function handler(event) {
    var request = event.request;
    var headers = request.headers;

    var authString = 'Basic ' + (authUser + ':' + authPass).toString('base64');

    if (
        typeof headers.authorization === 'undefined' ||
        headers.authorization.value !== authString
    ) {
        return {
            statusCode: 401,
            statusDescription: 'Unauthorized',
            headers: {
                'www-authenticate': {value: 'Basic'}
            }
        };
    }

    return request;
}
```

### [解決方法]Basic認証を特定のURLのみ除外する＆CloudFrontでビヘイビアを追加

#### 1. CloudFront関数の変更

```
    var uri = request.uri;

    // URL に /.well-known/ が含まれている場合は何もしない。それ以外の場合は Basic 認証を設定する。
    if (uri.includes('/.well-known/')) {
       return request;
    }
```

#### 2. ビヘイビアの追加

設定しているクラウドフロントのビヘイビアに以下の設定を追加する。

パスパターンに`　.well-known/acme-challenge/*`
キャッシュポリシーに`キャッシュの無効化`
を設定し、該当キャッシュを削除する。

### [感想]そりゃそう

CloudFrontを実装した際は、オリジンのcronを確認すべきですね、、、
良い勉強になりました！！
Firefox addon with qbittorrent(torrent client)

# torrentファイルのダウンロードを快適にしたい

[FOSS Torrents](https://fosstorrents.com/)
[Alternative downloads | Ubuntu](https://ubuntu.com/download/alternative-downloads)
こちらでオープンソース関連のディストリビューションなどのtorrentが配布されているわけですが、ブラウザのFirefoxからtorrentをダウンロードするのに良さそうな、アドオンとtorrentクライアントの組み合わせを検討していました。

# 求めていたこと
torrentファイルの場合、ファイル本体のサイズが大きいため、ブラウザとは関係ない形でダウンロードすることが望ましい。つまり、
1. Firefoxを終了させても、ダウンロードが継続される。
1. torrentをクリックしたら、torrentクライアントにダウンロードを委託する。

# 検討の結果
+ torrentクライアントはGUI有りのqbittorrent
コマンドラインではqbittorrent-nox
+ アドオンは[Torrent Control](https://addons.mozilla.org/ja/firefox/addon/torrent-control/?utm_source=addons.mozilla.org&utm_medium=referral&utm_content=search)

に決定しました。

# インストール
Ubuntu,Debian系
```
sudo apt install qbittorrent qbittorrent-nox
```
Arch系
```
sudo pacman -S qbittorrent qbittorrent-nox
```

# 使い方
まずqbittorrentの設定で、Web UIを有効にします。
```
http://127.0.0.1:8080/
```
上記がWeb UIのURLで、ユーザーとパスワードは、標準でユーザーが「admin」,パスワードが「adminadmin」です。
アドオンのTorrent Conrtolにユーザ名などを設定しておくと、アドオンアイコンをクリックすれば、Web UIも開けるので便利です。

qbittorrentのGUIクライアントを一回起動しておけば、あとはバックグラウンドで動いてくれていそうです。ブラウザを閉じても安心ですね。
Web UIさえあれば、GUI版クライアントは不要だという人の場合には、qbittorrent-noxをdaemonモードで起動して常駐させることが便利かもしれません。
```
qbittorrent-nox -d
```
ブラウザを利用する前に、あらかじめ一度、qbittorrentを起動しておく必要があるので、常駐させておけば、手間は省けますが、起動スクリプトを用意しておく必要がありますね。起動時のアプリケーションの指定できるディストリビューションでは、そこに追加しておくのも手だと思います。

もちろん、多くの人にとっては、常時、アプリを起動しておく必要性は高くないはずなので、torrentだけ、別のダウンロード専門のアプリを利用するのも一つの手です。
たとえばコマンドのaria2でもtorrentのダウンロードはできるので、そちらを利用するか、他のGUIのダウンロード専門のアプリにリンク(URL)を渡せばいいのですから。

# コマンドライン例
```
qbittorrent-nox https://releases.ubuntu.com/23.10.1/ubuntu-23.10.1-desktop-amd64.iso.torrent
```
```
aria2c -c https://releases.ubuntu.com/23.10.1/ubuntu-23.10.1-desktop-amd64.iso.torrent
```

試してみたところ、なぜだかUbuntuのtorrentダウンロードだけ、aria2cだとピアが増えなくて、遅かったです。普通にisoをそのままダウンロードするほうが良いくらいでした。
理由はわかりませんでしたが、qbittorrentで試すと、ピアが増えて、ダウンロード速度が十分でていました。
他のtorrentファイルではaria2で、遅くなったことはなかったので、ちょっと戸惑いました。
dhtの通信がうまくいっていないみたいで、ファイアウォールかなにかの問題で、うまくいかないっぽい。
他のPCのdht.datをコピーしたら、早くなったし、他のtorrentクライアントだと問題ないので、なにか解決策がありそうですが、とりあえず保留です。

# 補記
Ubuntu標準でインストールされているTransmissionを使わなかった理由は、torrentにwebソースが含まれていると、webサーバに多数の同時接続を行うみたいで、結構な負荷をかけることになりそうだったからです。設定で、改善するのかもしれませんが、サーバー側からアクセス制限を受ける可能性があるので、やめておきました。（自前サーバで試したところ、DoS判定となるくらい、多数の接続が行われ、fail2banに捕捉されました。標準設定のままだと、注意が必要そうです。）
NTemacs でうろ覚えのディレクトリ、ファイル名から開く

## やりたいこと
ディレクトリ名、ファイル名、うろ覚えしているときでも、emacs上でファイルを探して開きたい。しかも高速に。

## 課題1
find-file-in-project (https://github.com/redguardtoo/find-file-in-project )　という、サブディレクトリも検索して曖昧検索可能lispがあるが、標準でfindコマンドを使うらしく低速で待ち時間が長く辛すぎる。

## 対策1
findの代わりに fd ( https://github.com/sharkdp/fd )　を使おう。windowsなので、chocoで入れる。

## 課題2
fdを使うようにinit.elに設定したが、見つけたファイルをうまくひらくことができない。なぜだ。
```init.el
(require ' find-file-in-project))
(setq ffip-project-root "c:¥¥¥¥projects")
(setq ffip-find-executable "c:¥¥¥¥ProgramData¥¥¥¥chocolatey¥¥¥¥bin¥¥¥¥fd")
(seta ffip-use-rust-fd t)
```

## 対策2
```find-file-in-project.el
ffip-select-and-open-file　function内で、

(find-file file)

している箇所を、

(find-file (concat (ffip-get-project-root-directory) file))

にする。
```
## 結果
emacs 上で、M-x find-file-in-project を呼び出したら、
爆速でプロジェクトルート配下のファイルリストが表示され、
絞り込んで選択したら、ファイルが開くようになった。

# 所感
複数プロジェクト掛け持ちでソフトウェア開発している私みたいな人にはちょっとうれしいTIPSであって欲しい。
マルチモーダルモデル（LMM）の中身についてわかりやすく説明します

## 背景
ここ1週間、マルチモーダルのモデルが非常に増えました。
多くの有名IT企業が、自社のLLMを基にトレーニングされたLMMを公開しました。
今日はマルチモーダルモデルの中身（LMM）について説明したいと思います。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/a338aa33-8496-ebec-ced5-acaf4d35a267.png)



## 1.マルチモーダルとは
マルチモーダルとは、テキスト、画像、音声など異なる種類の情報を統合して処理するのことを指します。
最初のマルチモーダルモデルは、２年前OpenAIが公開された「CLIP」というモデルになります。
しかし、今までCLIPを利用しているケースはそれほど多くありません。理由は非常にシンプルで、異なる種類の情報を同時に処理するより、それぞれ分けて処理した方が性能が高いからです。
今年になってからLLMの強さがみんな感じましたので、LMMのトレーニングも活発に行われるようになりました。

## 2.マルチモーダルモデルの中身について
ほとんどのLMMはCLIPをベースとしてトレーニングしましたので、CLIPの中身について詳しく説明したいと思います。
一言でまとめると、CLIPは「テキストと画像をそれぞれの数字構成listに変換して（embedding）、それらを同じ場所（ベクトル空間）内でペアのものを近づくようにする」ということです。
例えば、リンゴの画像と「リンゴ」という単語があります。
リンゴの画像は画像用のモデルを用いて、ベクトルＡ：[3,4,6,7,8,4] に変換します。（CLIPはVision Transformer)
「リンゴ」という単語はテキスト用のモデルを用いて、ベクトルＢ:[2,4,5,6,7] に変換します。（CLIPはBERT）
その後は、ベクトルＡとベクトルＢを同じベクトル空間において、リンゴの画像は事前に「リンゴ」であるとアノテーションされていますので、ベクトルAとベクトルBはペアであることは分かります。
最後は、最適化アルゴリズム（adamとか)を使って、ベクトルＡとベクトルＢができるだけ近づくようにトレーニングします。（ここで損失関数が使われます）
トレーニングの流れは下図の通りとなります。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/d256cc45-05ee-242b-a172-36faa5a1a960.png)


CLIPが公開されてからBLIPやBLIP2などもありました。
チューニング方法はそこまで違いがなくて、データを増やしたり、レイヤーを追加したりでチューニングされています。
（最近のLMMモデルも基本的にはCLIPのやり方で、テキストのモデルをBERTから自分のLLMに変換する＋アノテーションで作ってもらった高品質な画像データを入れることでトレーニングしてます）



## 3.最近のLMMモデル
この１週間で結構多くのLMMが公開されました。
注目されているモデルは：
Microsoftの「LLaVa」：Vision Transformer + Llama2
Googleの「PaLi-3」：Vision Transformer + Bard
「BaKLLaVa-1」: Vision Transformer + Mistral
「fuyu-8b」: Transformerの開発者がトレーニングしたモデル

これらのモデルに関して比較するような記事はこれから公開されると思います。GPTくらいの性能があればLMMのfinetuningも流行る可能性が高いと思います。
ハードルはさらに高くなりますが、画像であってもベクトルベースであり、LLMとそこまで変わりはないと考えます。
ちなみに「fuyu-8b」に関しては、最近すごい話題になってますので、試してみたいと思います。

fuyu-8b: 

https://huggingface.co/adept/fuyu-8b

CLIP論文：

https://arxiv.org/abs/2103.00020
SSHで叩かれたコマンドを記録する

# モチベーション

デプロイメントツールなどで、SSHで対象のサーバに入ってよしなに色々してくれるものがあります。
中で何やってるのか見てみたいなーという時がちょこちょこあるのですが、あまりピンとくる方法がなく、いつも時間切れで諦めてしまってました。

今回またそういう要件が出てきたので、再挑戦してみようと思います。

# SSHのコマンドログを取る方法　基本方針

できるもの、できないものあるのですが、頭の整理のために並べてみます。

## A. SSHDのロギングの機能を使うーNG

ログインの成否までは出せますが、中で叩いたコマンドはログに出ません。

## B. ログイン時に呼び出されるShellに細工する

なんだかんだで現実的なのは、これですね。

## C. 通信を横抜きーNG

したところで暗号化してるんですから。。。

## D. プロキシを通す

Paramikoとか、、、？
現状Bのほうが筋が良さそうなので、まずはBで頑張って見ることにします。

# Shellの細工方針

ググって調べた方針を整理します。

## a. ログイン時に呼び出すシェルを、細工したスクリプトに置き換える

うまく行きそうだったのですが、後述のtrapの仕込みがうまく行きませんでした。
最後にbash -iを呼び出す際にtrapがそちらに引き継がれず。
exec側の方はうまく行ったのですが。。

トライしたのは以下。

```
$ echo $SHELL
/usr/local/bin/mtsh

$ cat /usr/local/bin/mtsh
#!/bin/bash

MT_LOGDIR=/var/log/sshlogs/

function log_history {
  echo $(date) $$ $BASH_COMMAND >> ${MT_LOGDIR}/history_${USER}
}
readonly -f log_history
trap log_history DEBUG EXIT ERR RETURN

exec &> >(tee -a >(awk '{print strftime("[%Y/%m/%d %H:%M:%S] "),$0} {fflush()}' >> ${MT_LOGDIR}/log_${USER}))

bash -i

exit
```

## b. プロファイルに仕込みを入れる

対話型でSSHに入るときと、コマンド実行だけさせるときで、読み出されるプロファイルが変わります。
.bashrcであればどちらのケースでも読まれるらしいので、そこに仕込みを入れます。
入れる内容は以下の２つ。

### b-1. exec &> を仕込んでおく

以下を実行することで、標準出力と標準エラー出力をteeに食わせます。
実装は以下を参考にさせていただきました。
https://zenn.dev/lovegorira/articles/62849db9f25012

```
$ cat ~/.bashrc
...
MT_LOGDIR=/var/log/sshlogs/
exec &> >(tee -a >(awk '{print strftime("[%Y/%m/%d %H:%M:%S] "),$0} {fflush()}' >> ${MT_LOGDIR}/log_${USER}))
...
```

teeの後がちょっとひねってあり、ログに書き出す前にawkで時刻を頭につけるようにしています。
また、&>にすることで、標準出力と標準エラーを両方拾っています。
エラーも拾っておきたいというよりは、、ターミナルの頭の「[user01@localhost ~]$」の部分が標準エラー出力になるようでして、それを拾いたかった、という方が強いです。

### b-2. trapでコマンドが叩かれる度にログを出す関数を呼び出します。

以下を参考にさせていただきました。
https://www.beex-inc.com/blog/linuxbashhistory

コマンドの結果の表示は拾えないのですが、叩いたコマンドは拾えます。
b-1で情報は包含しきれているのですが、別の用途で拡張するときに使えそうなので、仕込んでおくことにします。

b-1,2を実装した.bashrc配下の通り。

```
$ cat ~/.bashrc
...

# User specific aliases and functions
MT_LOGDIR=/var/log/sshlogs/
function log_history {
  echo $(date) $$ $BASH_COMMAND >> ${MT_LOGDIR}/history_${USER}
}
readonly -f log_history
trap log_history DEBUG

exec &> >(tee -a >(awk '{print strftime("[%Y/%m/%d %H:%M:%S] "),$0} {fflush()}' >> ${MT_LOGDIR}/log_${USER}))
```

# まとめ

とりあえずSSHで叩いたログが拾える状態になりましたが、ツールが叩く処理の中でリダイレクトをいじっている場合にb-1と干渉しないか？という感もあり。
軽く使ってみて様子を見てみようと思います。
archlinuxでclamavを使う

Linuxを使っていますが、chromeで、ウェブを閲覧しているとウィルスにやられました。clamavというアンチウィルスソフトを使ってみようと思います。

### インストール

```
sudo pacman -S clamav
```

### ウィルス・データベースのアップデート

```
sudo freshclam
```

### 準備

感染ファイルを隔離するディレクトリINFECTEDを作っておきます。

```
sudo mkdir /root/INFECTED
```


### 実行

テストです。このままでも実行可能です。
トップディレクトリを/にとり、ログファイルを/root/clamscan.logに出力し、感染したファイルを/root/INFECTEDに移動させます。

```
su
<パスワード入力>
cd ~
clamscan -i -v --log=/root/clamscan.log --move=/root/INFECTED -r / &
```

### 一般ユーザーからコマンド一発で実行できるように.bashrcを書き換える

.bashrcに下記を追加します。
nohupでバックグラウンドジョブにし、niceでジョブの優先順位を最低にし、ログファイルを/root/clamscan.logに出力し、感染ファイルを/root/INFECTEDに移動するようにし、第一引数をトップディレクトリにとり、nohupの標準出力と標準エラー出力を/root/clam.outにまとめて出力するようにします。

```
function clamscan {
    sudo sh -c "nohup nice -20 clamscan -i -v --log=/root/clamscan.log --move=/root/INFECTED -r '$1' >/root/clam.out 2>&1 &"
}
```

追加したあとは
```
source .bashrc
```
で更新しておきましょう。

### 実行

```
$ clamscan $HOME
```

ウェブ閲覧に感染したウィルスなので、ホームディレクトリ以下に感染してると思い、$HOMEからスキャンします。

### コメント

clamavでは引っかからなかったため、adblockerを変えたり、`rm -rf .config/google-chrome`をしたりしましたが、結局chromeの「設定をリセットする」で駆除できたようです。
【Next.js】Imageコンポーネントで優先度の高い画像を設定する

以下のように`priority={true}`を記述すると画像の優先度が高くなり、プリロードされるようになります。

```tsx
    <Image
      src="me.png"
      alt="Picture of the author"
      width={500}
      height={500}
      priority={true}
    />
```
Tableau Lightning Webコンポーネントのシームレスな認証を試してみた(Tableau Cloud版)

## 前提
・2023.3の新機能でリリースされたTableau Lightning Web コンポーネントのシームレスな認証機能になります。
・Salesforce管理者権限が必要になります。
## 参考ヘルプ
https://help.tableau.com/current/online/ja-jp/lwc_seamless_auth.htm

https://help.tableau.com/current/online/ja-jp/connected_apps_troubleshoot.htm
## 手順
### 1.Salesforce側でTableau組み込みを設定
①Salesforceホーム画面の歯車→「設定」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/3d2d33f3-73b6-916a-d3f8-c81050717801.png)
②検索ボックスからTableauと入力し、「Tableau組み込み」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/7868ece8-6ea8-361f-afff-45220a8f0e47.png)
③
トークンベースのシングルサインオン認証を有効化：☑︎
Tableauユーザー ID 項目を選択：Tableauに渡すユーザ識別子を選択(Salesforce と Tableau でユーザー アイデンティティに一致するフィールドを選択)
発行者URL、JWKS URIをメモ帳にコピーしておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/1c60a4f3-59e9-beec-92eb-3b487fbb69e1.png)

### 2.Tableau Cloud側で連携アプリを設定
①Tableau Cloudの「設定」→「連携アプリ」→「新しい連携アプリ」→「OAuth2.0信頼」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/fa057ed2-66b1-7968-daf9-65be63a9c824.png)
②以下の情報を設定し、作成をクリック
発行URL：1-③でコピーした発行者URLをペスト
JWKS URI：1-③でコピーしたJWKS URIをペスト
接続済みアプリを有効にする：☑︎
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/e80ebb10-a8d8-fc9c-19dd-20d81ad87e86.png)
### 3.Tabelau CloudのビューをSalesforceへ埋め込む(Tableau Cloud側)
①Tableau Cloudから埋め込みたいビューを開く
②「共有」をクリックし、ビューの共有ウィンドウから、「リンクのコピー」、「サイトIDのコピー」をクリックし、メモしておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/cc7e648e-2ef0-d578-7cd6-a32d28a445d4.png)
### 4.Tabelau CloudのビューをSalesforceへ埋め込む(Salesforce側)
①レコードページの歯車→「編集ページ」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/6f9c14a5-e5b2-14c5-a940-209ff2932a43.png)
②コンポーネントからtableauを入力し、「Tableauビュー」を画面にドラックアンドドロップする
③右側のTableauビュー設定で、以下を設定し、「保存」をクリック
TableauビューのURL：3-②の「リンクのコピー」
デフォルトの認証トークン：☑︎
サイトID：3-②の「サイトIDのコピー」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/4aa5425f-aa52-d4b2-a662-d10023da7319.png)

④フィルターを設定したい場合は、TableauとSalesforceのフィールドマッピングを設定
Tableauの詳細な検索条件：Tableauのフィールド名
Salesforceの詳細な検索条件：Salesforceの項目名
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/c845c425-1dad-fade-c142-b56124112f79.png)
⑤レコードページを表示し、Tableauビューが表示されてることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/99c619df-a8a0-dc78-64dd-b8327a96df0c.png)

以上
Javaプロセスをリストアップする

Javaプロセスをリストアップする

```java
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;

public class ListRunningProcesses {

    public static void main(String[] args) {
        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        List<String> inputArguments = runtimeMxBean.getInputArguments();

        System.out.println("JavaプロセスID: " + runtimeMxBean.getName());

        System.out.println("Javaプロセスの起動引数:");
        for (String arg : inputArguments) {
            System.out.println(arg);
        }
    }
}
```
ProxmoxのLXCコンテナ内でDockerをネスト利用する（NestedDocker）

# はじめに

本番用途じゃないんだけど、ちょっとだけ動作確認したい。でもその環境でDockerを動作させたい。とかいうとき。
わざわざVM建てる手間が惜しいので、LXCコンテナでDockerをネスト利用する方法。

LXCコンテナを作成する際に、以下のオプションを有効にしておけばOK
* ☑非特権コンテナ
* ☑ネスト

GUIで設定するなら以下のようになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334782/db6e4da2-92c7-512f-5cb4-fb259c2aed30.png)



# CLIでネスト対応コンテナを作成する

のまえに、CTテンプレートをダウンロードしておく。
「データセンター」→「作成したノード名」→「local」→「CTテンプレート」から「テンプレート」をクリックすると、以下のようなダイアログが出るので、必要なものを選択して「ダウンロード」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334782/c7e5c31e-1a37-b927-d3c7-8723751f37b1.png)

すると、実ファイルは `/var/lib/vz/template/cache/` にダウンロードされる。


ダウンロードしたテンプレートを利用して以下でLXCコンテナを作成
（ここでは ubuntu22.04 を利用している）

```:コンテナ作成
pct create 999 /var/lib/vz/template/cache/ubuntu-22.04-standard_22.04-1_amd64.tar.zst \
  --hostname lxc-cli \
  --features nesting=1 \
  --unprivileged 1 \
  --ssh-public-keys /root/.ssh/authorized_keys \
  --rootfs local-lvm:8 \
  --cores 4 \
  --memory 4096 \
  --swap 0 \
  --net0 name=eth0,bridge=vmbr0,ip=10.254.10.100/24,gw=10.254.10.254,tag=10 \
  --start 1

# DHCPの場合は以下 
#  --net0 name=eth0,bridge=vmbr0,ip=dhcp,tag=10 \
```

このCTテンプレートはSSHサービスが動作していないので `pct enter 999` でコンソールログインしてDockerインストールする

```:(コンテナ内で)Dockerインストール
# curlが導入されていないのでインストールする
apt install -y curl

# いつもの手順
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
```

動作チェック

```:(コンテナ内で)hello-worldで動作確認
$ docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

AplineLinuxを単騎で立ててちょっとシェルでログインしたいなー、とか、ちょっとツールの動作確認したいなー、とかのとき。

```:(コンテナ内で)AlpineLinuxにログイン
$ docker run -it alpine sh

/ # cat /etc/*release*
3.18.4
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.18.4
PRETTY_NAME="Alpine Linux v3.18"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

/ # apk add bind-tools -q
/ # dig -v
DiG 9.18.19
```

# コンテナ削除

```:コンテナ削除（＆関連するリソースも削除）
pct shutdown 999 && pct destroy 999 --purge
```
【AWS】PuttyでEC2にSSH接続する際の設定方法

## はじめに
EC2にSSH接続する際、Puttyの設定方法を備忘録として残しておきます。

## Puttyのダウンロード
Puttyを使うにはまずローカルにダウンロードしてきてあげる必要があります。
[Putty公式](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)からインストーラをダウンロードしてインストールしましょう。
その時ついでに**Puttygen**というものもダウンロードしてインストールしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577451/bf8c4bc5-e7f8-0b31-98ed-179f7ca4a8b6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577451/1c170448-a1e5-448c-1dc5-57ef6d1b3528.png)

## Puttygenでキーを変換する

PuttyではSSH接続する時にPPK形式のキーが必要になるらしいです。
EC2立てる時に作成したキーペアがPEM形式の場合はPuttygenで形式変換してあげましょう。

1. PuTTYgenを開き、「Load」ボタンをクリックしてPEM形式のキーファイルをロードします。

2. キーファイルがロードされたら、「Save private key」ボタンをクリックしてPPK形式でキーファイルを保存します。

## Puttyを設定する
1. PuTTYを開き、左側のカテゴリパネルで「Session」を選択します。
2.「Host Name (or IP address)」フィールドに、EC2インスタンスのパブリックDNSまたはパブリックIPアドレスを入力します。
3.「Port」フィールドには、22を入力します（デフォルトのSSHポート）。
4. 左側のカテゴリパネルで「Connection」->「SSH」->「Auth」を選択します。
5.「Private key file for authentication」フィールドに、Puttygenで変換したPPKファイルを指定します。

## 接続
上記設定が完了したら「Open」をクリックして接続します。

`login as:`を聞かれるので`ec2-user`を答えてあげれば接続できるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577451/03ea4869-017c-7324-3533-27d25f3b408f.png)
M1&fish環境にMojoをインストールする🔥🐟

※2023年10月20日に公開した[Zennの記事](https://zenn.dev/miyakei/articles/001c94802a4e64)と同様の内容です。

2023年10月19日(木)にMojo SDKがApple Silicon(M1&M2環境)で利用可能になりました！

![](https://storage.googleapis.com/zenn-user-upload/d5a04127367a-20231020.png)

今回はM1&fishでセットアップする方法を解説していきます。

【セットアップの概要】
1. [Modular開発者コンソール](https://www.modular.com/)に移動し、ログインもしくはアカウント作成をします。
2. [ダウンロードページ](https://developer.modular.com/download)で「Set up on Mac」を選択し、掲載されている1〜5の手順に沿って進める。
3. config.fishで環境変数の設定をする。
4. インストール完了

## Modular開発者コンソールでログインorアカウント作成をする

[こちら](https://www.modular.com/)でログインまたはアカウント作成をしてください。

## Mojo SDKダウンロードページに進む

[ダウンロードページ](https://developer.modular.com/download)で「Set up on Mac」を選択する。(Intel環境の方はIntel版を選択してください。)

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

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

## Modular CLIをインストールする

```
curl https://get.modular.com | sh - && \
modular auth 【コンソールに表示されている値を入力してください】
```

## Mojo SDKのインストール

```
modular install mojo
```

![modular install](https://storage.googleapis.com/zenn-user-upload/d6e8631beccd-20231020.png)

実行をする際に```modular auth```の実行を求められる場合があるため、その際は以下のコマンドを実行する。
```
modular auth 【コンソールに表示されている値を入力してください】
```

modularコマンドには他にもあり[こちら](https://docs.modular.com/cli/#commands)で確認できます。

## mojoコマンドを使えるようにパスを通す

インストール完了後、以下のメッセージが表示される。
※一部パス名の書き換えを行なっています。
```
🔥 Mojo installed! 🔥

Mojo's Python virtual environment created at /【ローカルパス名】/.modular/pkg/packages.modular.com_mojo/venv

Now run the following commands if you are using bash:

echo 'export MODULAR_HOME="/【ローカルパス名】/.modular"' >> ~/.bashrc
echo 'export PATH="/【ローカルパス名】
source ~/.bashrc

If you are using ZSH, run the following commands:

echo 'export MODULAR_HOME="/【ローカルパス名】/.modular"' >> ~/.zshrc
echo 'export PATH="/【ローカルパス名】/.modular/pkg/packages.modular.com_mojo/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

Then enter 'mojo' to start the Mojo REPL.

For tool help, enter 'mojo --help'.
For more docs, see https://docs.modular.com/mojo.
```

```
If you are using ZSH, run the following commands:
```
「zsh環境の方は以下のコマンドを実行してくださいね」と表示されていますね。
ここからが今回の記事の本題で、コンソールに表示されているzsh環境用のパス設定部分をfish用に置き換えて設定していきます！

## config.fishにパス変数を設定する

.config/fish/config.fishを開く
```
vi ~/.config/fish/config.fish
```

iを入力してインサートモードの状態で以下の変数を貼り付ける。
```
# Mojo
set --export MODULAR_HOME "$HOME/.modular"
set --export PATH "$HOME/.modular/pkg/packages.modular.com_mojo/bin:$PATH"
```

escまたはctrl + cを入力してインサートモードを抜けた状態で保存する。
```
:wq
```

## 設定した環境変数を読み込ませるためターミナルを再起動する

ターミナルの再起動をして環境変数を読み込ませてください！

## パスが通ったか確認する

```
mojo -v
```

実行結果
![mojo -v](https://storage.googleapis.com/zenn-user-upload/7bd71dd4725e-20231020.png)

## セットアップ完了🔥

コンソール画面からHello Worldを実行してみましょう。
```mojo```を実行した後、```print("Hello, world!")```と入力して実行してください！

```
mojo
Welcome to Mojo! 🔥

Expressions are delimited by a blank line.
Type `:quit` to exit the REPL and `:mojo help` for further assistance.

  1> print("Hello, world!")
  2.
Hello, world!
```

VS Codeで実行される方は[こちら](https://marketplace.visualstudio.com/items?itemName=modular-mojotools.vscode-mojo)の拡張機能をインストールし、実行してください！

## まとめ

今回はM1&fish環境にMojo SDKのインストール&セットアップを解説しました。
本記事が参考になりましたらいいねを頂けると幸いです！
Happy Hacking!
WDC-X1201DU3-BをLinuxで使う！ 

この度、自宅のLinuxサーバのWifiアダプターをWi-Fi6にしたいと考え、お値段もお手頃なELECOMのWDC-X1201DU3-Bを購入しました。

https://www.elecom.co.jp/products/WDC-X1201DU3-B.html

しかし、このWi-FiアダプターはWindows 10/11のみのサポートなので、Linuxでは通常利用することができませんでした。

ネットを探してもなかなか情報が見つからず、途方にくれていましたが、Windowsのデバイスドライバを見たときに、このアダプターは「Realtek 8832AU Wireless LAN WiFi6 USB NIC」が内蔵されていることがわかりました。そして、Realtek 8832AUのドライバを調査したところ、`rtl8852au`というLinux用のドライバがサポートしていることがわかり、無事WDC-X1201DU3-BをLinuxで使うことができました。

https://github.com/lwfinger/rtl8852au

この記事では、このrtl8852auをインストールして利用できるようにする方法について書きたいと思います。といっても、rtl8852auをREADMEに従ってインストールするだけです。

※なお、動作確認はUbuntu23.04で行いました。

## 1. 認識しているか確認する

まず、そもそもWiFiドライバが認識しているか確認してみます。

```bash
$ lsusb
...
Bus 003 Device 006: ID 056e:4020 Elecom Co., Ltd 802.11ax WLAN Adapter
```

この、「056e:4020 Elecom...」みたいなやつがWDC-X1201DU3-Bです。これが表示できていたらOKです。

## 2. 必要なパッケージのインストール

ドライバインストールの前に、インストールに必要なパッケージをインストールします。

```bash
$ sudo apt-get update
$ sudo apt-get install make gcc linux-headers-$(uname -r) build-essential git
```

## 3. rtl8852auをクローンする

次に、rtl8852auをGithubからクローンします。

```bash
$ git clone https://github.com/lwfinger/rtl8852au.git
```

## 4. make & make install

クローンしたリポジトリをビルドします。

```
$ cd /path/to/rtl8852au
$ make 
$ sudo make install
```
※`/path/to/rtl8852au`はクローンしたリポジトリのURLを表してます

ビルドが終わったら後、Ubuntuを再起動するとWifi6が使えるようになると思います！

## dkmsを使って自動更新

上記のmakeコマンドを実行することでWifiルーターは使えるようになりますが、カーネルがアップデートされたら再度ドライバをインストールしないといけなくなります。
なので、dkmsというソフトウェアを使って、カーネルが更新されてもrtl8852auが使えるように設定しておきましょう。

```bash
$ sudo apt install dkms
$ cd /path/to/rtl8852au
$ sudo dkms add .
$ sudo dkms build rtl8852au -v 1.15.0.1
$ sudo dkms install rtl8852au -v 1.15.0.1
$ modinfo 8852au
$ modprobe 8852au
```

## おまけ

実は、当初rtl8852auは元々WDC-X1201DU3に対応していませんでしたが、この記事を書く前に自分のプルリクが採用されたので、今はめでたくインストールするだけで使えるようになっているはずです :tada: 

でもその結果、この記事はREADMEのインストール手順をそのまま書くだけになってしまった・・・。