OmniAICreator/Qiita-1.07M huggingface dataset:
link/unlinkはハードリンクの作成・削除コマンド。シンボリックリンク用ではないしファイルも削除する管理者用コマンド。

## はじめに

`unlink` コマンドは**ハードリンクを削除するコマンド**です。コマンド名に link と入っているから勘違いしている人がいるようですがシンボリックリンクを削除するために作られたコマンドではありません。**`unlink` コマンドの反対は `link` コマンド**です。

**`link` コマンドはハードリンクを作成**します。その反対なので `unlink` コマンドはハードリンクを削除するコマンドと言って良いでしょう。リンクを削除してどこからもリンクされなくなったファイルは消えるので`unlink` コマンドはファイルも削除します。シンボリックリンクファイルもファイルなので削除されます。

## link/unlink はシステム管理者用のコマンド

**`link`/`unlink` はシステム管理コマンド**です。本来は一般ユーザー用ではありません。Solaris 11 では `/usr/sbin` 以下にあります。

https://docs.oracle.com/cd/E62101_01/html/E62876/unlink-1m.html

```console:Solarisではsbin以下にある
$ which link unlink
/usr/sbin/link
/usr/sbin/unlink
```

```console
$ which rm
/usr/bin/rm
/usr/bin/ln
```

Linux などでは一般ユーザー用コマンドとして扱われているような気がしますが。

GNU unlink のドキュメントによると、一部のシステムでは `unlink` コマンドはディレクトリを削除することが出来ます。別のシステムでは特権ユーザーでなければ `unlink` コマンドを実行することは出来ません。GNU 版はディレクトリを削除することありません。

https://www.gnu.org/software/coreutils/manual/html_node/unlink-invocation.html

> On some systems unlink can be used to delete the name of a directory. On others, it can be used that way only by a privileged user. In the GNU system unlink can never delete the name of a directory.

## rm を使ったほうが安全

Solaris は **rm を使ったほうが安全**と言っています。

> While linked files and directories can be removed using unlink, it is safer to use rm(1) and rmdir(1) instead. See rm(1) and rmdir(1).

**訳** リンクされたファイルやディレクトリは unlink を使って削除できるが、代わりに rm(1) や rmdir(1) を使った方が安全である。rm(1) と rmdir(1) を参照のこと。

シンボリックリンクの削除には `rm` コマンドを使います。オプションを何も指定しなければ、`rm` コマンドでシンボリックリンクを消そうとしてシンボリックリンク先のファイルが消えたりすることはありません。**`rm` コマンドには「削除してもよろしいですか？」と確認する機能がついています**。その時に削除対象が通常のファイルかシンボリックリンクかも教えてくれます。ファイルごとに確認されるのがウザいなら `-i` の代わりに `-I` を使いましょう。正しく使えば **`rm` コマンドは `unlink` コマンドよりも安全**です。

`rm` コマンドを使う時に、何も考えずに `-r` や `-f` オプションを付ける癖はなくしましょう。シンボリックリンクファイルを消す時に `-r` がいらないのはすぐに分かりますよね？なんでも `-f` を付けているとせっかくの削除時の確認機能が無意味なものになってしまいます。確認メッセージを読まずに「はい」「はい」「はい」とクリックしているのと同じことです。オプションの意味を知って、必要なときだけ指定するようにしましょう。

## シンボリックリンクの削除は unlink のほうが安全という謎理論

この理論を唱えている人は、`unlink` コマンドをシンボリックリンクを削除するコマンドだと勘違いしています。

なぜなら、もし勘違いしていないなら「ファイルの削除には `rm` コマンドよりも `unlink` コマンドを使ったほうが安全」と言っているはずだからです。

ファイルの削除に `rm` コマンドを使っていながら、シンボリックリンクの場合だけ（ファイルを削除する） `unlink` コマンドを使うというのではおかしな話ですね。

結局のところ、必要ないのに `-r` オプションを付けるなという話です。

## さいごに

使いたいのなら `unlink` でシンボリックリンクを削除しても構いませんが、`unlink` はハードリンクを削除するシステム管理コマンドで通常のファイルまでも消してしまうコマンドです。
nginx で バーチャルドメインを同一IPアドレスでhttp/3(QUIC) 運用する方法

# TDLR

nginx 1.25以降で バーチャルドメインを同一IPアドレスでhttp/3(QUIC)運用する方法
nginx.confでの``reuseport``は1つのポートに対して1箇所のみ指定しましょう

# Install

HTTP/3が使えるようにコンパイルされたnginxが各自用意してください

# e.g.
エッセンシャルなところだけ
2つ目以降の``listen``には ``reuseport`` をつけずに ``quic``だけ記述するのがミソ
あと、ワイルドカード証明書を使う場合は、その証明書を使っている全てのバーチャルドメインで同一の設定にしておかないと、コネクションを使い回そうとするのでエラーが出たりするので注意

nginx.conf

    server {
        listen       443 ssl default_server;
        listen       [::]:443 ssl default_server;

        listen 443 quic reuseport;
        listen [::]:443 quic reuseport;
        http2 on;
        http3 on;

        server_name _;

        location / {
            root    /default_root/;
        }

    }


    server {
        listen  443 ssl;
        listen  [::]:443 ssl;
        listen  443 quic;
        listen  [::]:443 quic;
        http2 on;

        server_name  virtual1.example.org;

        location / {
             add_header Alt-Svc 'h3=":443"; ma=86400' always;
        }
    }


    server {
        listen  443 ssl;
        listen  [::]:443 ssl;
        listen  443 quic;
        listen  [::]:443 quic;
        http2 on;

        server_name  virtual2.example.org;

        location / {
             add_header Alt-Svc 'h3=":443"; ma=86400' always;
        }
    }

# Conclusion

* 全ての``listen``にreuseportをつけるとハマる。
* 設定するのは最初の一つだけ
運用保守に向いている人の特徴をまとめてみた

## はじめに
運用保守は定型作業で誰でも出来る印象を持たれますが、向き不向きに大きく分かれるお仕事です。
いろんな現場での経験を振り返って運用保守の向いている方についてまとめてみました。

本記事に記載した内容に該当しないなくても、向いていないということではないです。
**何よりも業務を継続できることが大事です。**
**運用保守の業務を継続していると自然と本記事に記載していることが出来る様になっていきました。経験が大きいです。**

私の経験をもとに記載しています。
今後運用保守の仕事をする方は参考にしてください


## 向いている特徴
### 時間に正確な方
運用作業は本番環境で作業することが主なため、作業時間は厳守です。
そのため、時間に正確である必要があります。
運用作業の開始連絡は作業時間ちょうどでいつも行っています。

### 柔軟に時間を調整できる方
突発的な作業依頼や急ぎのお問い合わせ、障害が発生することにより、予定が急に変わることはあります。急でもスケジュールを調整する必要があります。

### マルチタスクが得意な方
運用は複数の依頼作業依頼が来て、マルチタスクで期限内で終わらせる必要があります。
期限内に終わらせない場合は、例えばSSL証明書更新依頼などの依頼は本番環境に影響が出ます。
そのため、たくさんの作業依頼を定時内で終わらせるスキルが必要です。

### 仕事中に割り込みが発生しても苦痛ではない方
一つの仕事を集中しようとしても、日々様々な作業依頼やお問い合わせが来るため、
チームの方から急ぎで質問がきたり又は急ぎな依頼が来た際は柔軟に対応する必要があります。

### 繰り返し同じ作業をしても苦にならない方
運用作業は運用改善は大切ですが、繰り返し同じ作業がある場合があります。
定型作業が苦痛ではない方があっています。
良くない例ですが運用でカバーする体制もあります。どう見ても効率が悪いと思っても
なかなか改善までに時間がかかるケースもあります。

### コミュニケーション取ることが好きな方
運用保守はチーム内とお客さんとのコミュニケーションがたくさん発生します。
チームに苦手な方がいても、積極的にコミュニケーションを取る必要があります。


### 操作を見られながら作業しても平気な方
運用作業は2名体制で作業するため、一人でじっくり仕事をするというよりはチームワークで仕事をします。
運用作業を確認者から見られながら作業します。長時間作業になることもあります。

### 日々スキルアップ出来る方
運用保守はプログラムの知識を付けて運用の自動化をする
linuxの知識を付けて障害対応に活かす  など

例えばAnsibleで自動化して運用作業を短縮化する場合があります。
サーバーの状態が日々変化するため、手順書通りに操作してもうまくAnsibleが想定外の動作をする場合があります。その場合はAnsibleの知識を付ける必要があります。

**手順書通りに操作しても、万が一に備えて理解していない作業はしないことが大事です**

### 運用改善出来る方
無駄な作業があれば自動化することで品質がよくなる且つ作業効率が上がる運用改善が出来ることが一番良いです。ただ何となく流れ作業になり繰り返し疑問を抱かずに作業を続けるのは長期的に見てコスト削減につながらないし良くないです。

・自動化でミスが起きないこと
・業務の時間を短縮できること

運用改善するにはお客さんやメンバーの許可を得る必要があります。そのため、納得してもらうための
コミュニケーション能力も大事です。

## あれば尚可
### 休日や夜間帯作業や連勤作業に臨機応変に調整できる方
運用保守は本番環境など影響が出る作業は夜間帯や休日作業になることがあります。
その場合は臨機応変に調整して対応する必要があります。
どうしても出来ない方はチームの誰かにお願いして対応してもらうこともよくあります。
保守フェーズで現場によってリリース作業が近づいてきた時に連勤がある現場がありました。


## まとめ
運用保守は現場によりますが、残業が平均30時間以上ありました。
そのため、現場によりますが定時上がりで定型作業で終わる仕事ではない場合があります。
障害があれば定時後作業になるし、本番影響がある依頼作業では夜間帯から作業もあります。
運用保守といっても現場によって労働環境は変わります
現在はリモートワークで障害があれば休日、夜間帯も電話を取る体制で働いています。
障害の頻度が少ないため、問題なく続いています。


運用保守メインでちょうど9年目の経験をまとめました。
本記事がお役に立てれば嬉しいです。
【Ruby on Rails】rails-erdでテーブル構造をER図で見れるようにしたい

# はじめに
どうしてもテーブルが多くなってくると`schema.rb`だと見づらくなり、テーブルの関連性を理解するのに時間がかかってしまいます。
そこで`rails-erd`という`gem`を使うと**ER図**を出力できるそうなので、試してみました！
# 実装環境
 - Ruby 3.2.2
 - Ruby on Rails 7.0.7
 - Homebrew

# 導入手順

```terminal
brew install svn
```

```terminal
brew install graphviz
```
::: note warn
```
brew install graphviz
```
実行時に下記のエラーが出たので、`svn`も同時に読み込んでいます。
```ruby
You must: brew install svn
Error: graphviz: Failed to download resource "netpbm"
Failure while executing; `/usr/bin/env svn checkout https://svn.code.sf.net/p/netpbm/code/stable /Users/keisukesakuma/Library/Caches/Homebrew/netpbm--svn --quiet -r 4686` exited with 1. Here's the output:
You must: brew install svn
```
:::

```ruby:Gemfile
group :development do
  gem "rails-erd"
end
```

```ruby
bundle install
```
```ruby:config/environments/development.rb
config.eager_load = true #falseからtrueに変更
```

```ruby#
rake erd
```

ルートディレクトリ配下に`erd.pdf`というファイルが生成されます。
テーブルが１つなので見応えがないですが、無事に出力することができました！

[![Image from Gyazo](https://i.gyazo.com/3c6611187f462fc206809ca83ad9e941.png)](https://gyazo.com/3c6611187f462fc206809ca83ad9e941)
【GAS】GSSはJSONで保管すると約1.5倍高速になる

<h1>何のため？</h1>

GASでWebアプリ等を作成していると、データをJSON形式で保管したいことが頻発するので作成しました。CacheServiceやPropertiesServiceだと容量に制約があり、大量のデータ保管ができません。そのため、GSSを保管場所として利用してみます。

<h2>速度比較</h2>
GSSに保存するのなら、わざわざJSONにする必要性を感じないかもしれません。
下のように、普通に表に入力しても良さそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953722/d96bde76-7671-b43b-c447-9a0900ec913b.png)
※全てダミーデータです。https://testdata.userlocal.jp/

しかし、速度の観点から、JSONとして出力した方がより良いと言えます。結論から言うと、およそ1.5倍高速になります。
具体的なコードとともに確認します。

<h3>【表で保管した場合】</h3>
<h4>サンプルコード</h4>

```js
function doGet(e) {

  const id = e.parameter.id;

  const values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("dummy").getDataRange().getValues();
  return ContentService.createTextOutput(JSON.stringify(values.find(v => v[0] === id))).setMimeType(ContentService.MimeType.JSON);
  
}
```
<h4>結果</h4>

平均して<b>1.1776秒</b>でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953722/175edc76-3b01-30cb-5097-c4de22f3c307.png)

<h3>【JSONで保管した場合】</h3>
ちなみに、このような感じで、JSONの文字列を分割して複数のセルに跨らせています。
利用する際は、これらを連結してからJSON.parseを使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953722/3739cb93-190d-6146-2969-61ca0c561212.png)


<h4>サンプルコード</h4>

```js
function doGet(e) {

  const id = e.parameter.id;

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("json");
  const values = sheet.getRange("A:A").getValues().flat().join("");
  const result = JSON.parse(values)[id];

  return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
  
}
```

<h4>結果</h4>

5回の平均は <b>0.8106秒</b> でした。表で保管した場合の1.5倍ほど高速で動きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953722/9e21c29c-1f52-b917-f8e2-0ad835f94781.png)

<h1>クラス化</h1>

JSON形式で保存するには、以下の二つの作業が必要です。

- Object -> String -> 分割  (JSONの保存)
- String -> 連結 -> Object  (JSONの取り出し)

GSSのセルは一つにつき50000文字までなので、必要に応じて分割が必要です。

いちいち書くのが面倒なので、クラス化します。
```js
class GSSDB_{

  /**
   * @param {SpreadsheetApp.Sheet} sheet
   */
  constructor(sheet){

    this.sheet = sheet;

  }

  /**@param {object} object */
  save(object){

    const arr = JSON.stringify(object).match(/.{1,10000}/g).map(v => [v]);
    this.sheet.getRange(1,1,arr.length,1).setValues(arr);

  }

  fetch(){

    return JSON.parse(this.sheet.getRange("A:A").getValues().flat().join(""));

  }

}
```

具体的な使用イメージは下記の通りです。

```js
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("sheetname");
  const GSSDB = new GSSDB_(sheet);
  const json = {
      //色々なデータ
  };

  //値の保管
  GSSDB.save(json);
  //値の取り出し
  const obj = GSSDB.fetch();
```

以上です。
UE5学习日记 2023/10/10

GameMode变更
1.在Project->Map & Modes里可以将Default GameMode改为自己创建的GameMode
![スクリーンショット 2023-10-10 213550.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574567/f4289a9a-678d-0d6d-fbaf-6349201ddba0.png)

2.在Player Start里可以override
![スクリーンショット 2023-10-10 214028.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574567/28d1d412-e74a-4e40-13d5-bc943543bc26.png)

应该正常情况下都用1来设定GameMode。
GameMode应该是定义游戏规则用的。
问题1:　GameMode和level的关系是什么


collision碰撞
collision Presets可以对碰撞进行设置
![スクリーンショット 2023-10-10 214531.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574567/fdacdef3-743d-3f5a-3dd2-268d3fbc56f0.png)
BlockAllDynamic可以动态被任何物体阻挡
OverlapAllDynamic可以动态与任何物体重叠

问题:动不动态有什么区别

今天学到的
蓝图 
Open level可以实现进入下一关和开始游戏
ceil 向上取整
Subtraction 输入1-输入2
SetText 画面上显示文字

widgt
widget所有元素都可以在detail最上面设为graph可用变量(is variable)
添加按钮后，可以在按钮detail最下方找到案件event
Greaph左侧可以添加变量等
获取和给添加的变量赋值都可以直接拖动左侧对应变量到右侧实现
オブジェクト指向

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/2d37ef01-1423-9494-4046-6291a749a04a.png)
１：UML 
UML(Unified Modeling Language)は、オブジェクト指向によるシステム分析・設計に用いる図法です。クラス間の関係を表したり、オブジェクト間のメッセージ（指示）の意流れを表したりするのに便利です。

・ユースケース図
　利用者から見て、システムがどのように機能するのかを表す図です。システムの機能を表すケース、ユースケースを利用してシステムから情報を受け取るアクターがあります。

・クラス図
　クラス間の関係を表す図です。集約ー分解関係は♢マークで、汎化ー特化関係は△マークで表します。集約ー分解関係では多重度を書くこともできます。

・シーケンス図
　オブジェクト（インスタンス）間のやり取りを時系列で表す図です。どのインスタンスが、どのインスタンスのメソッドを呼び出すのかを表現します。
脅威インテリジェンスの教科書

https://www.amazon.co.jp/%E8%84%85%E5%A8%81%E3%82%A4%E3%83%B3%E3%83%86%E3%83%AA%E3%82%B8%E3%82%A7%E3%83%B3%E3%82%B9%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E7%9F%B3%E5%B7%9D-%E6%9C%9D%E4%B9%85/dp/4297124572

本書を手に取った背景
CISSPを受験するに当たり気になったので読んでみたくなった。
Mitter　Attackについてちゃんと調べたことがなかったけど、本書に記載がありそうだった。

本書のテーマ
脅威インテリジェンスアナリスト向けに知識・技術が身につけられる。

個人的なポイント

１，
SIGINT:セキュリティ機器から取得するアラート
OSINT:様々な媒体からの情報
HUMINT：内部ユーザー、セキュリティーベンダーからの情報

２，IOC
indicaroe of compromise・侵害指標。実際に発生した攻撃手法を特定するための技術的特性情報

３，脆弱性管理のアプローチ
情報収集→トリアージ→対応

４，ドメインフローティング
あまり聞いたことがなかったので気になった。CDNの機能を悪用し、C2通信を正規通信に予想王こと。

５，Mitre Att&ckの６つの要素
tactics,戦術
techniques,技術
common knowledge,手順
advisery group,グループ
software,ソフトウェア
mitigration,対策

６，blue teamの注目すべきポイント
不審なアウトバウンド通信、特権ユーザによる異常な行動など

７，インシデント対応プロセス
事前準備→特定→封じ込め→根絶→復旧→教訓→最初に戻る

８，収集すべき技術指標

９，工作フェーズ
攻撃グループについて更に調査を行うこと。将来の攻撃の予防をする


今後やれること
・SIEMやXDRの調査方法を考える

まとめ
これ一冊で脅威の分析に関する考え方はわかるように思う。
【SwiftUI】PhotosPickerで画像を選択した後、正方形に切り取りできるようにする

# はじめに
画像を選択した後に画像を切り取りたいことがあると思います。
`allowsEditing`というフラグをtrueにすることで選択した後に切り取りの画面に遷移させることができます。

# 実装
```swift
import SwiftUI

public struct PhotoPickerView: UIViewControllerRepresentable {
    @Environment(\.dismiss) private var dismiss: DismissAction

    @Binding private var image: UIImage?

    public init(image: Binding<UIImage?>) {
        self._image = image
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    public func makeUIViewController(context: Context) -> UIImagePickerController {
        let uiImagePickerController = UIImagePickerController()
        uiImagePickerController.delegate = context.coordinator
        uiImagePickerController.sourceType = .photoLibrary
        uiImagePickerController.allowsEditing = true
        return uiImagePickerController
    }

    public func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
}

extension PhotoPickerView {
    public class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: PhotoPickerView

        public init(_ parent: PhotoPickerView) {
            self.parent = parent
        }

        public func imagePickerController(
            _ picker: UIImagePickerController,
            didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
        ) {
            if let image = info[.editedImage] as? UIImage {
                parent.image = image
            } else if let image = info[.originalImage] as? UIImage {
                parent.image = image
            }
            parent.dismiss()
        }
    }
}
```

# 使い方
```swift
import SwiftUI

struct ContentView: View {
    @State private var isPresentedPhotoPickerView = false
    
    @State private var image: UIImage?

    var body: some View {
        VStack {
            Button {
                isPresentedPhotoPickerView = true
            } label: {
                Text("PhotoPicker表示")
            }
            
            if let image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300)
            }
        }
        .sheet(isPresented: $isPresentedPhotoPickerView) {
            PhotoPickerView(image: $image)
                .ignoresSafeArea()
        }
    }
}
```

# おわり
公式でサポートされているおかげで簡単に実装ができますね！
Javaで「スキャナで取得した値を指定したデータ型の値として取得する」の動作を確認してみた

# 概要

Javaで「スキャナで取得した値を指定したデータ型の値として取得する」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/start/scanner/index2.html

# 実装

以下のファイルを作成しました。
```JSample2_3.java
import java.util.Scanner;
import java.util.InputMismatchException;

class JSample2_3{
  public static void main(String[] args){
    Scanner scanner = new Scanner(System.in);

    try{
      System.out.println("年齢を入力してください");
      int old = scanner.nextInt(16);

      System.out.println("年齢は" + old + "です");
    }catch (InputMismatchException e){
      System.out.println("数値を入力してください");
    }
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample2_3.java 
$ java JSample2_3 
年齢を入力してください
2F
年齢は47です
```

# まとめ

何かの役に立てばと。
【Dockerfile】Chromeのバージョンに合わせて、ChromeDriverをインストールする

## 環境

- Ruby on Rails 7.0.7
- Capybara 3.39.2
- Selenium-webdrivers 4.11.0
- Docker 23.0.5
- Docker Compose 2.17.3

## 背景

- あるとき、E2Eテストがほとんど失敗する現象が起きた
  - ChromeとChromeDriverのバージョン差異が原因
  - DockerfileでChromeとChromeDriverをインストールしている
    - バージョン115以降は、別のURLからダウンロードしなければならなかった
    - [バージョン114まで](https://chromedriver.chromium.org/downloads)
    - [バージョン115以降](https://googlechromelabs.github.io/chrome-for-testing/)


## 対応内容

- DockerfileのChromeDriverインストール部分のURLをバージョン115以降のURLに変更
  - Chromeのバージョンを変数に代入して、差異が起きないように設定

``` Dockerfile

# Chromeをインストール
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
    echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list && \
    apt-get update && apt-get install -y google-chrome-stable

# ChromeDriverをインストール
RUN apt-get update && apt-get install -y unzip graphviz && \
    CHROME_VERSION=$(google-chrome-stable --version | cut -d " " -f3) && \
    echo "Chrome_Version: ${CHROME_VERSION}" && \
    curl -sS -o /root/chromedriver_linux64.zip https://storage.googleapis.com/chrome-for-testing-public/$CHROME_VERSION/linux64/chromedriver-linux64.zip &&\
    unzip ~/chromedriver_linux64.zip -d ~/ && \
    rm ~/chromedriver_linux64.zip && \
    chown root:root ~/chromedriver-linux64/chromedriver && \
    chmod 755 ~/chromedriver-linux64/chromedriver && \
    mv ~/chromedriver-linux64/chromedriver /usr/bin/chromedriver

```

## 参考文献

- [ChromeDriverの公開方法がChrome 115から変更された](https://qiita.com/yatt/items/58c380ada912f8b75e06)
- [Docker 環境での ChromeDriver ver. 115 以降の取得先変更対応](https://zenn.dev/route06/articles/78c30c6627a932)
- [ChromeDriverのv.115以上で動かない時の対応](https://qiita.com/sgash708/items/5040d16a231394016b19)
Swiftでバケツツールの塗りつぶし

# Swiftでバケツツールの塗りつぶし

ペイントアプリのバケツツールのように、閉じた領域を指定した色で塗りつぶす操作を、[Accelerate frameworkのflood fills](https://developer.apple.com/documentation/accelerate/vimage/vimage_operations/applying_a_flood_fill_to_an_image/applying_flood_fills_to_an_image?changes=___11&language=objc)を用いて簡単に実現できます

![Frame 293.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214313/3970d20a-1641-33db-6cb3-8c1c0b43de2f.png)


# 実装
CGImageをvImageに変換し、vImageFloodFill_ARGB8888を使って、塗りつぶしを始める点を含む閉じた領域を指定した色で塗りつぶします

```swift
func floodFill(input: CGImage, atPoint point: CGPoint, withColor color: UIColor) -> CGImage {
    // 1. 入力画像のフォーマットとバッファの初期化
    var format = vImage_CGImageFormat(cgImage: input)!
    var inputBuffer = vImage_Buffer()
    vImageBuffer_InitWithCGImage(&inputBuffer, &format, nil, input, vImage_Flags(kvImageNoFlags))
    defer { inputBuffer.free() }

    // 2. 塗りつぶし色の変換と実行
    var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
    color.getRed(&r, green: &g, blue: &b, alpha: &a)
    var fillColor: [UInt8] = [r, g, b, a].map { UInt8($0 * 255) }
    vImageFloodFill_ARGB8888(&inputBuffer, nil, vImagePixelCount(point.x), vImagePixelCount(point.y), &fillColor, 8, 0)

    // 3. 結果のCGImageの取得
    let resPtr = vImageCreateCGImageFromBuffer(&inputBuffer, &format, nil, nil, vImage_Flags(kvImageNoFlags), nil)!
    return resPtr.takeRetainedValue()
}
```


## 1. 入力画像のフォーマットとバッファの初期化

最初に、CGImageからvImage_Bufferを作成します
deferキーワードを使って、このバッファが関数を抜ける際に解放されるように設定しておきます

:::note warn
**CGImageFormatのColor spaceについて**
関数名はARGB8888ですが、入力画像がモノクロの場合はモノクロ、アルファ無しのRGB場合はアルファ無しのRGBのように、入力画像のcolor spaceの色でしか塗りつぶすことができませんでした
入力画像のcolor space以外で塗りつぶしたい場合は、フォーマットを変える必要がありそうでした
:::

```swift
var format = vImage_CGImageFormat(cgImage: input)!
var inputBuffer = vImage_Buffer()
vImageBuffer_InitWithCGImage(&inputBuffer, &format, nil, input, vImage_Flags(kvImageNoFlags))
defer { inputBuffer.free() }
```

## 2. 塗りつぶし色の変換と塗りつぶしの実行
UIColorのrgbaをUInt8の配列に変換し、塗りつぶしを実行します

```swift
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
var fillColor: [UInt8] = [r, g, b, a].map { UInt8($0 * 255) }
vImageFloodFill_ARGB8888(&inputBuffer, nil, vImagePixelCount(point.x), vImagePixelCount(point.y), &fillColor, 8, 0)
```

## 3. 結果のCGImageの取得
最後に、塗りつぶし処理の結果を取得します
vImageCreateCGImageFromBuffer 関数を使用して、vImageバッファから結果のCGImageを生成します
この関数は、処理が完了したら解放される必要のないCGImageを返します
そのため、takeRetainedValue関数を使用して、結果のCGImageを保持し、関数の戻り値として返します

```swift
let resPtr = vImageCreateCGImageFromBuffer(&inputBuffer, &format, nil, nil, vImage_Flags(kvImageNoFlags), nil)!
return resPtr.takeRetainedValue()
```

# まとめ
ペイントアプリのバケツツールのように、閉じた領域を指定した色で塗りつぶす操作を、[Accelerate frameworkのflood fills](https://developer.apple.com/documentation/accelerate/vimage/vimage_operations/applying_a_flood_fill_to_an_image/applying_flood_fills_to_an_image?changes=___11&language=objc)を用いて簡単に実現できました
この関数を使えば、色の塗りつぶし処理を簡単に実現でき、ペイントツールや画像処理で活用できそうです
M1 Macでpsychがインストールできない問題と解消法

## 私のOS状況
- M1Macを使用
- CPUアーキテクチャはarm64
```zsh
$ uname -m
arm64
```
## エラー状況
RailsをAPIモードで作成しようと以下のコマンドを実行
```zsh
rails new uber-eats-like --api
```
すると
```zsh
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

checking for yaml.h... yes
checking for yaml_get_version() in -lyaml... no
libyaml not found
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

To see why this extension failed to compile, please check the mkmf.log which can be found here:

/Users/[名前]/.rbenv/versions/3.0.5/lib/ruby/gems/3.0.0/extensions/arm64-darwin-22/3.0.0/psych-5.1.0/mkmf.log

//省略
An error occurred while installing psych (5.1.0), and Bundler cannot continue.
```
`libyaml`が見つからず、それに依存した`psych (5.1.0)`がインストールがされず、エラーとなった。
## 解決手順
#### 1.Homebrewを使用して`libyaml`をインストール
```zsh
brew install libyaml
```
#### 2.`psych`をインストール
```zsh
gem install psych
```
上記と同じエラーが発生。
#### 3.エラー文に`the mkmf.log`を見に行けとあるので行ってみた
```zsh
To see why this extension failed to compile, please check the mkmf.log which can be found here:

/Users/[名前]/.rbenv/versions/3.0.5/lib/ruby/gems/3.0.0/extensions/arm64-darwin-22/3.0.0/psych-5.1.0/mkmf.log
```
```mkmf.log
ld: warning: ignoring file /usr/local/lib/libyaml.dylib, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
```
`libyaml.`をmacOS-arm64 用にビルドしていますが、macOS-x86_64 用にビルドされたファイルとリンクしようとしよとしているとのこと。
#### 4.Homebrewでインストールした`libyaml`の情報を見てみる
```zsh
brew info libyaml
```
```zsh
1cb8a391276afb7--libyaml--0.2.5.arm64_ventura.bottle.tar.gz
==> Pouring libyaml--0.2.5.arm64_ventura.bottle.tar.gz
🍺  /opt/homebrew/Cellar/libyaml/0.2.5: 10 files, 351.3KB
==> Running `brew cleanup libyaml`...
```
Homebrewを使ってlibyamlのバージョン0.2.5をARM64アーキテクチャ（arm64_ventura）用にインストールし、それが成功していることがわかる。

**どうゆうことなのか。。。。**

#### 5. libyamlのパスを指定して再試行
```zsh
gem install psych -- --with-yaml-dir=/opt/homebrew/Cellar/libyaml/0.2.5
```
- `--with-yaml-dir=`でlibyamlのライブラリとインクルードファイルがあるディレクトリを指定。

https://e-words.jp/w/%E3%83%98%E3%83%83%E3%83%80%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.html

- /opt/homebrew/Cellar/libyaml/0.2.5は、先程`brew info libyaml`で確認した`libyaml`がインストールされているディレクトリです

`psych-5.1.0`のインストールに成功しました！
```zsh
Building native extensions with: '--with-yaml-dir=/opt/homebrew/Cellar/libyaml/0.2.5'
This could take a while...
Successfully installed psych-5.1.0
Parsing documentation for psych-5.1.0
Done installing documentation for psych after 0 seconds
1 gem installed
```
#### 6.再度、RailsをAPIモードで作成しようと以下のコマンドを実行
```zsh
rails new uber-eats-like --api
```
エラーも出ずに作成できました！
## まとめ
- 依存関係: psychはYAMLデータを解析または生成するためのRubyのライブラリで、その動作にはlibyamlというCライブラリが必要だった。

- ローカル環境: システム全体に影響を与えずに、特定のディレクトリにlibyamlをインストールしている場合や、複数バージョンのlibyamlが存在する場合に、どのlibyamlを使用するか明示的に指定する必要があった。
## 参考サイト
https://github.com/rbenv/ruby-build/discussions/2118
Blade Component はキャメルケースで書く

最近 Blade Component を使ってます。
[PSR-12](https://www.php-fig.org/psr/psr-12) とかだと

- スネークケースで変数は書こうね
- 関数名はローワーキャメルケースで書こうね

って感じなので、そんな感じでやってたら若干ハマりました。

#### NG
```html
<x-layout test_message="なんかのテストメッセージ" />
```

#### OK
```html
<x-layout testMessage="なんかのテストメッセージ" />
```

[PSR-12: 4.7 Method and Function Calls](https://www.php-fig.org/psr/psr-12/#47-method-and-function-calls) をよく見ると、引数はキャメルケースみたいです。（むずすぎいい！！）

# まとめ
|内容|書き方|例|
|---|---|---|
|変数|スネークケース|test_val|
|関数|ローワーキャメルケース|testMethod|
|引数|ローワーキャメルケース|testArg|
mojoの勉強のためにライフゲームのコードを書く

pythonの云千倍速いという触れ込みのmojoの勉強を始めたかったので、定番のライフゲームの実装を行う。
簡単のため、ターミナル上で勝手に表示されるだけのものにする。
使用したのバージョン「mojo: 0.3.0」

### 実装したコード

```python
from memory import memcpy
from random import randint, seed
from time import sleep

struct Lifegame:
    var board: DTypePointer[DType.int8]
    var next_board: DTypePointer[DType.int8]
    var rows: Int
    var cols: Int

    fn __init__(inout self, rows: Int, cols: Int):
        self.board = DTypePointer[DType.int8].alloc(rows * cols)
        self.next_board = DTypePointer[DType.int8].alloc(rows * cols)
        randint(self.board, rows * cols, 0, 1) #0/1 random initialization
        self.rows = rows
        self.cols = cols

    fn exec_game(self):
        while(True):
            print("\033[;H\033[2J")
            self.draw_board()
            sleep(0.1)
            self.next_step()

    fn next_step(self):
        for y in range(self.rows):
            for x in range(self.cols):
                let alive_around: Int = self.num_alive_around(x,y)
                if alive_around == 2:
                    self.next_board.store(self.cols * y + x, self.board.load(self.cols * y + x))
                elif alive_around == 3:
                    self.next_board.store(self.cols * y + x, 1)
                else:
                    self.next_board.store(self.cols * y + x, 0)

        memcpy(self.board, self.next_board, self.rows * self.cols)
        

    fn num_alive_around(self, x: Int, y: Int) -> Int:
        var num_alive: Int = 0
        for dy in range(-1,2,1):
            for dx in range(-1,2,1):
                if dx==0 and dy==0: continue
                if x + dx < 0 or self.cols <= x + dx: continue
                if y + dy < 0 or self.rows <= y + dy: continue
                let idx: Int = self.cols * (y + dy) + x + dx
                if self.board.load(idx)==1:
                    num_alive += 1
        return num_alive 

    fn draw_board(self):
        for y in range(self.rows):
            var one_line: String = ''
            for x in range(self.cols):
                one_line += '@' if self.board.load(self.cols * y + x)==1 else '-'
            print(one_line)


fn main():
    seed()
    var new_game = Lifegame(15,30) # size of game screen
    new_game.exec_game()
```


実行結果(途中)
```$ mojo lifegame.mojo
------------------------@-----
--@--------------------@@-----
-@-@--------------------------
-@@---------------------------
------------------------------
---------------@@-------------
--@@-----------@@-------------
--@@--------------------------
------------------------------
-------------------@@---------
-------------------@@---------
------------------------------
---@@-------------------------
--@-@---@@--------------------
---@----@@--------------------
```


### 感想
- ほぼpythonを書いているような感じだった。
- 所有権の話をしっかり理解できていない
- memory系の処理に明るくなく、load, storeの使い方が不明
- 見てて楽しい

### 参考
- ライフゲームの実装
  - [JavaScriptでライフゲームを作成する](https://qiita.com/gushwell/items/ed7f4039e5c240a387ff)
  - [各言語によるLifegameの実装](https://github.com/tex2e/lifegame/tree/master/c%2B%2B)
FastAPIでLangChainのレスポンスをストリーミングで返却する

Langchainをお使いの皆様。
Streaming対応はお済みでしょうか。

今回はストリーミングできるようにしてみます。
↓下記は私が作っている拡張機能にLangChainを接続してみたものになります。
こんな感じでストリーミングできます。


![bandicam-2023-10-10-20-54-18-575.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418662/bd079967-2dd6-3f59-4509-2d85e7e04e28.gif)

コードの全体像
```python
import threading
import queue
import uvicorn
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from langchain.chat_models import ChatOpenAI
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout_final_only import (
    FinalStreamingStdOutCallbackHandler,
)
from langchain.schema import (
    HumanMessage,
    SystemMessage,
    AIMessage
)

app = FastAPI(
    title="LangChain",
)

class ThreadedGenerator:
    def __init__(self):
        self.queue = queue.Queue()

    def __iter__(self):
        return self

    def __next__(self):
        item = self.queue.get()
        if item is StopIteration:
            raise item
        return item

    def send(self, data):
        self.queue.put(data)

    def close(self):
        self.queue.put(StopIteration)

class ChainStreamHandler(FinalStreamingStdOutCallbackHandler):
    def __init__(self, gen):
        super().__init__()
        self.gen = gen

    def on_llm_new_token(self, token: str, **kwargs):
        self.gen.send(token)

def llm_thread(g, prompt):
    try:
        chat = ChatOpenAI(
            verbose=True,
            streaming=True,
            callback_manager=CallbackManager([ChainStreamHandler(g)]),
            temperature=0.7,
        )
        chat([SystemMessage(content="You are a poetic assistant"), HumanMessage(content=prompt)])

    finally:
        g.close()


def chat(prompt):
    g = ThreadedGenerator()
    threading.Thread(target=llm_thread, args=(g, prompt)).start()
    return g


@app.get("/question-stream")
async def stream():
    return StreamingResponse(
        chat("Write me a song about sparkling water."),
        media_type='text/event-stream'
    )


def start():
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)


if __name__ == "__main__":
    start()

```

ぜひお試しを。

>こちらに元のコードがあります。
>https://github.com/langchain-ai/langchain/discussions/1706
【Docker】「Cannot connect to the Docker daemon」が出てコンテナを起動できない時にやったこと

# 事象
Dockerの勉強でとあるリポジトリからクローンしたDockerのコンテナを起動しようとしたところ、
次のようなメッセージが出ました。

```
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
```
「Docker Daemonは起動している？」というメッセージが出てきてコンテナが起動できませんでした。

# 解決策
Docker Desktopを起動する。

コンテナを起動するための仕組みがDockerには備わっているみたいです。
今回はそれにあたるデーモンが動いていなかったため発生した事象でした。

> Dockerデーモンは Linux のデーモンプロセスで、Docker Engine API が呼び出されるのを待ち受けています。
> Dockerデーモンは、呼び出された Docker Engine API に応じて、イメージのビルドやコンテナの起動などを行います。

## 他にやったけどダメだったこと
### docker-compose.ymlで設定しているポートを変える
同じエラーが出ました。
### sudo service docker start
```
% sudo service docker start
Password:
sudo: service: command not found
%
```

# さいごに
Dockerを勉強中につまずいたので備忘も兼ねてまとめました。
誤っているところありましたらDocker強者の皆さんは教えてください。

# 参考

https://www.ogis-ri.co.jp/otc/hiroba/technical/docker/part6.html
【AzureML プロンプトフロー】検証記事まとめ

# プロンプトフローの記事まとめ
AzureMLのプロンプトフローの検証記事をまとめました。

+ [Ask Wikipedia](https://qiita.com/kkawano_neko/items/64fb88d4880953ac1a5d)
質問に対してWikipediaからのソース付きでChatGPTの回答を得られます

+ [Chat with Wikipedia](https://qiita.com/kkawano_neko/items/bf1c95fc920160cd26f7)
Ask Wikipediaのチャット版です

+ [Web Classification](https://qiita.com/kkawano_neko/items/4e60417fe6d1eceaeb00)
送ったURLの内容からカテゴリ分類を行います

+ [Q&A with Your Own Data Using Faiss Index](https://qiita.com/kkawano_neko/items/1a81b5fdec388c1d0e62)
Faiss Indexの埋め込み化を使ったQ&Aを作れます

+ [Bring your own Data QnA](https://qiita.com/kkawano_neko/items/117843936c3cbb2854e9)
Vector Searchの埋め込み化を使ったQ&Aを作れます

+ [Bring Your Own Data Chat Q&A](https://qiita.com/kkawano_neko/items/0963ba01a87d71f151af)
Bring your own Data QnAのチャット版です
Open Interpreterを試してみた

# はじめに
今回はOpen Interpreterをローカルから使ってみます。

# 環境
+ OS Windows 10(NVIDIA GTX 1650Ti,16GB RAM, i5-10300H CPU)
+ Visual Studio Code 1.73.1
+ Python 3.9

# Open Interpreter
Open Interpreterはファイルのアップロードやデータ分析ができるChatGPTの「Code Interpreter」をローカルでも可能としたツールです。

実行時間やファイルサイズなど制限なしで使えるみたいなので、いろいろ試してみます。
実行するときの注意点としては、ライブラリのインストールは次々と行うようになっているのでanacondaなどの仮想環境を使って実行をします。

## インストール
Open Interpreterを使うのに必要なインストールはたったのこれだけです。
```
pip install open-interpreter
```

## 実行
今回はGPT-4ではなく、無料でも使えるLlamaを使って実行していきます！

下記コマンドを実行します。
```
interpreter
```
すると、次のようにGPT-4かCode-Llamaを選択できるようになります。
もし、OpenAI APIキーを持っていればそれを入力すれば大丈夫です。
今回はないため、そのままEnterキーを押して次へ進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/cbb98558-d9ac-7341-f939-fd800ba3d9c4.png)

これでLlamaへ接続されました。
続いてモデルの選択を行います。それぞれパラメータ数が7B・13B・34Bの3つモデルから選べます。
今回は7B(70億パラメータ)のSmallを選択しました。選んだモデルはローカルにない場合は自動的にダウンロードされるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/a3b32b56-d5c9-00aa-4452-4e7e4964a064.png)

最後にGPUを使うかどうか聞かれるので、今回はY(Yes)を選択しました。

これでプロンプトが入力されるようになりました。
もし、コードの実行などその都度ユーザーに許可を求めたうえで実行したい場合には、そのままプロンプトを入力すれば大丈夫です。いちいち許可するのは面倒な場合は「interpreter -y」と入力してプロンプトを書きましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/7834aaf0-289d-1519-ea51-049bef2e225c.png)

さっそく日本語で「1から100までの和を求めるコードをPythonで書いて」と入力してみます。
日本語プロンプトは認識されたようで、少し待つと次のようにコードをすぐに書いてくれました。

このコードを実行するかどうか聞かれたので、「y」と入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/cda8c46a-61cd-e292-91ed-261bbcfd8faa.png)

すると、書いてくれたコードをさっそく実行してくれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/8b034488-f86d-b782-fb60-1f575788d168.png)

## 試しにデータ分析をお願いしてみる

Code Interpreterではファイルを渡してデータ分析もできることで話題になっていましたよね。
Open Interpreterでも同じことができるのか試してみようと思います。

まずはプロンプトにファイルの場所を教えてあげて、「データ分析をして」と入力します。

すると、R言語でコードを書いてくれました。
コードを実行するか聞かれたので、そのまま「y」を入力すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/343d7c58-db69-4d92-9f4a-d22fc367d922.png)

「指定したファイルが見つかりません。」と出ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/9b46af29-0e24-af26-440f-c08e18e84c2a.png)

Open Interpreterを実行したフォルダにデータを置いた場合は読み込みに成功しているようなので、それを試してみます。

参考記事

https://dev.classmethod.jp/articles/open-interpreter-demo/

今度は「データ分析をPythonで行ってください。データは./passengers.csvにあります。」と入力して実行します。

同じようにコードが生成されるので、これをさらに実行させます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/ff99b56a-4507-7002-c3e5-1a579dafe9b5.png)

エラーは出ていますが、ファイルの読み込みまではなんとかできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976188/e7d57b13-e206-01fa-94e9-ac28d1a35058.png)



Llamaではなく、GPT-4を使うとまた違った結果が得られるかもしれないですね。
Llamaでは実行時間がかかったり精度もあまり高くないように感じますが、GPT-4では結構良い精度で実行できるとのことなので試してみたいですね。
ウェイトリストについて調べてみた

## 概要

- 新しいサービスが公開される前に「ウェイトリストに登録！」みたいなページが表示されることがある。ウェイトリストについてなんとなく知ってるけど、ちゃんと知らなかったので簡単にまとめてみる。

## 意味

- ウェイトリスト（ウェイティングリスト）は`waiting list`のこと。（当たり前ですみません。）
- `waiting list for ~`で「~の順番待ち名簿」という意味になる。
- 「順番待ち名簿」や「キャンセル待ち名簿」といった意味があるらしい。

## サービスにおけるウェイトリスト

- Webサービス・その他アプリケーションにおいてウェイトリストも近い意味で「サービスが使えるようになるまで待ってる人の名簿」的な意味合いらしい。
- 機能が具体的に定義されているわけではなく、基本的なものだけでいうと下記のようなものだけの機能を提供するっぽい。
    1. ウェイトリストへの登録
    1. サービスが利用できるようになったらウェイトリストのメールアドレスに通知メールを送る
    1. 当該ユーザーが当該サービスに登録を行ったらウェイトリストから削除する
- サービスによっては下記の様なよりリッチな処理が行われることもあるらしい。
    1. 優先順位付け
        - ウェイトリストへの登録が早ければ早いほど当該サービスに早期アクセスできる。
    1. 順位共有機能
        - ウェイトリストの登録順位をSNSなどで共有できる機能を提供する。
    1. 待機時間の表示
        - ユーザーがサービス利用開始できるまでの時間を表示する。
    1. 招待制度
        - すでにウェイトリストへの登録を済ましているユーザーが他の人を招待し、その人が登録するとすでに登録を済ましているユーザーの順位が上がる。
        - 単体で実装されることは少なく、ウェイトリストの上位になることが重要な機能が実装されているものと併用されることがほとんど（優先順位付け、待機時間が短くなるなど）
    1. 体験版アクセス権
        - メインバージョン前のα版ないしはβ版を実際に触ることのできる権限がもらえる。

## 参考文献

https://eow.alc.co.jp/search?q=waiting+list&ref=wl
ESP32を使用してTeraterm上からリレーモジュールを操作する。

# はじめに

ESP32を使用してリレーモジュールをTeraTerm上から制御する。
安定化電源などは後ろに付いている制御端子(？)のShort / Openで
電源出力のON / OFFが出来るので安定化電源をPC上のteratermから操作が出来る。

# 説明

マイコンは以下のESP32のDevkitを使用
やることはGPIOを2つLOW HIGHするだけなのでGPIOが2個あってUSBインターフェースがあればESP32Devkitである必要は全くないです。
https://akizukidenshi.com/catalog/g/gM-13628/

購入したリレーモジュールはこれ↓
https://www.amazon.co.jp/gp/product/B08QJ3PNH3/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&th=1

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/7822d279-d16a-c51a-bab8-548e35f5a953.png)

DC+に5V、DC-にGNDを接続する。
基板上を見る感じフォトカプラ乗っているっぽいので、ちゃんと基板上のパターン追っていないけどリレーON時の逆起電力でマイコン破壊などは起きないと信じる。

そして
IN1 を ESP32の12
IN2 を ESP32の14
に接続する。

```
#include "Arduino.h"

// リレーのトリガピン設定
#define RELAY_1 12
#define RELAY_2 14

// コマンドを受信するためのグローバル変数
String command = "";

void setup() {
  Serial.begin(115200);

  // RELAY_PINを出力として設定
  // リレーはNCを使用しているので初期値はLOWで短絡
  pinMode(RELAY_1, OUTPUT);
  digitalWrite(RELAY_1, LOW);
  pinMode(RELAY_2, OUTPUT);
  digitalWrite(RELAY_2, LOW);
}

void loop() {
  // シリアルポートから利用可能なデータがある場合、それを読み取る。
  while (Serial.available() > 0) {
    char inChar = (char)Serial.read();
    command += inChar;

    // エンターで読み取る、
    if (inChar == '\n') {
      command.trim();  // 余分な空白の削除。

      // コマンド "r1 o" でリレー1をオープン
      if (command == "r1 o") {
        digitalWrite(RELAY_1, HIGH);
        Serial.println("Relay1 open");
      }
      // コマンド "r1 c" でリレー1をショート
      else if (command == "r1 c") {
        digitalWrite(RELAY_1, LOW);
        Serial.println("Relay1 short");
      }
      // コマンド "r2 o" でリレー2をオープン
      else if (command == "r2 o") {
        digitalWrite(RELAY_2, HIGH);
        Serial.println("Relay2 open");
      }
      // コマンド "r2 c" でリレー2をショート
      else if (command == "r2 c") {
        digitalWrite(RELAY_2, LOW);
        Serial.println("Relay2 short");
      }
      // その他のコマンドの場合はエラー
      else {
        Serial.println("Unknown command");
      }

      // コマンドリセット。
      command = "";
    }
  }
  delay(10);
}

```

これをESP32に書き込み、Teraterm上で
「r1 o」など規定のコマンドを打って送信すればリレーが開閉します。

ほなまた
erbファイルでTailwind CSS IntelliSenseのコード補完機能を使えるようにする

初めまして。RUNTEQというスクールで学習をしている、たかぎと申します。



Tailwind CSS IntelliSenseというvscodeの拡張機能をインストールすることで、htmlファイルではTailwindCSSのクラスの自動補完をすぐに使えたのですが、erbファイルだと設定をしないと使えないようです。
これについての記事があまりなかったので、説明しようと思います（私も教えていただいたものですが）。



設定は簡単です。
以下のコードをsetting.jsonに追加するだけです。

```setting.json
"tailwindCSS.includeLanguages": {
  "erb": "html"
}
```

公式に載っていたのですが、私はqiitaの記事ばかり探してしまいました。なっさけない。
https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss

以上です。あざした。
TDD（テスト駆動開発）について

# 1.はじめに
+ 自分が学んだものをアウトプットして見返すためです。
+ 内容は、メリットとデメリット、具体的なやり方です。

# 2.メリットとデメリット

| メリット | デメリット |
|:-:|:-:|
|  品質の向上 |  時間と労力 |
|  リファクタリングのサポート | 学習曲線 |
|設計の改善|テストの保守|
|自己文書化|全てのケースを網羅しきれない|
|信頼性の向上|過度の焦点|
|バグの早期発見|適さない場合もある|
|協力とコミュニケーション|テストケースの保守|
|自己満足感|テストのオーバーヘッド|

つまり、品質向上や信頼性の向上など多くの利点を期待できる。しかし、時間や労力がかかること、開発者の経験によるブレ幅で効果が異なる。簡単なスクリプト、緊急性のあるプロジェクトなど向いていないものもある。
アジャイル開発みたいに、開発者やステークホルダーが密なコミュニケーションがあるもの。品質向上を求めるものには向いている。

# 3.一連の流れ
要件から始まる
#### 1\. テストケースの作成（Redフェーズ）
+ 新しい機能の追加や既存のコードを変更を加えたい場合、それに関連するテストケースを作成する。
+ テストケースは、コードが期待される動作を評価するのが目的。この段階では、まだコードがないので、テストケースは失敗（Red）するはず。

``` sample.py
import unittest

class TestCalculator(unittest.TestCase):
    def test_addition(self):
        # 2 + 3 の結果が5であることをテストします
        self.assertEqual(add(2, 3), 5)  # この関数addはまだ存在しない

```
この段階では、'add'関数がないので失敗するはず。

#### 2\. テストケースの実行（Redフェーズ）
+ 作成したコードを実行する。
エラーメッセージが表示される。テストが失敗したことが示される。正常である。

#### 3\. コードの実装（Greenフェーズ）
+ テストケースが失敗したと確認したら、テストが成功するようにコードを実装する。
+ このコードは、最小限の機能を実装することが一般的で、まずはテストをパスさせることを優先させる。
+ コードを書いたら、再度テストケースを実行し、テストが成功を確認する。
成功したら、この段階のコードは安定していると言える。

```sample.py
def add(a, b):
    return a + b

```
'add'関数を実装して、テストケースは成功するはず。

#### 4\. リファクタリング（Refactorフェーズ）
+ コードがテストをパスするようになったらリファクタリングを行う。コードの品質を向上させ冗長性を削除し、可読性を高めるためにコードを改善させる。
+ テストが成功した状態で行われるため、コードが壊れる心配はない。
+ この例では必要なし。複雑になったら行う。
#### 5\. テストの再実行（Greenフェーズ）
+ テストコードを再度実行し、リファクタリングによってコードが壊れていないかの確認をする。

#### 6\. 繰り返し（１に戻る）
+ 上記の手順を必要な分だけ行う。
+ 新しい機能を追加する場合や既存のコードを変更する場合、それに対応する新しいテストケースを作成し、コードを追加または変更していくサイクルです。
+ 例で言うと、機能の追加や変更（三平方の定理や加減乗除など）を追加したいならテストケースを作成して（以下略


# 4.所感
テスト駆動開発は、荒削りしてから徐々に細かく加工して完成品に近づけるものと感じた。

# ex.参考資料
ChatGPT-3.5
[Recursion](https://recursionist.io/)
保護フィルムを表面 市場の主要ドライバー、研究目標 2023-2031: メーカー、地域、サイズ、予測とのシェアによる分析

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574472/f6fdc979-d34c-92f4-a090-3c58a59a9bbe.png)
"保護フィルムを表面 市場に関する最新のレポートは、今後数年間のプラスの成長率を示唆しています。このレポートは、詳細な 保護フィルムを表面 市場の概要を、業界の粗利益、開発手法、ビジネス戦略、課題と機会、投資計画、および経済的影響とともに提供します。アナリストは過去のデータを研究し、それを現在の市場シナリオと比較して、今後数年間の軌道を決定しました。また、市場の概要、定義、および範囲を含む徹底的な調査レポートを提供します。

レポートのサンプル コピーを入手するには - https://www.industryresearch.biz/enquiry/request-sample/17434250

生産、価格、収益（価値）、および各メーカーを含む、トップメーカーによるグローバル保護フィルムを表面市場競争：

- Nitto Denko Corp
- Bischof + Klein SE & Co. KG.
- Chargeurs S.A.
- ZAGG
- Solar Gard (Saint-Gobain)
- PowerSupport
- DUNMORE Corporation
- Alvest SAS
- XPEL
- Surface Guard, Inc.
- Toray Advanced Film Co., Ltd.
- Argotec
- MOSHI, H
- Eastman
- Orafol, BELKIN
- BodyGuardz.
- Polifilm GmbH
- Avery Denison
- Tredegar Corporation
- Halo Screen Protector Film
- Crystal Armor
- 3M
- Spigen
- OtterBox
- Tech Armor

「最終報告書には、この業界に対する COVID-19 の影響の分析が追加されます。」
- レポートの第 2.3 章では、業界に対する COVID-19 の発生の影響が完全に評価されました。特別な期間に、保護フィルムを表面 に対して完全なリスク評価と業界の推奨事項が作成されました。この章では、COVID-19 前と COVID-19 後の市場も比較します。
- 第 2.5 章では、業界チェーンの観点からの COVID-19 の影響の分析について説明します。
- さらに、第 6 章から第 10 章では、COVID-19 が地域経済に与える影響について考察しています。

Covid-19 の影響がこのレポートでどのようにカバーされているかを理解するには - https://www.industryresearch.biz/enquiry/request-covid19/17434250

企業プロファイル、製品の写真と仕様、容量、生産、価格、コスト、収益、連絡先情報などの情報を提供するグローバル 保護フィルムを表面 マーケット。上流の原材料と計装、および下流の需要分析が追加で分配されます。グローバル 保護フィルムを表面 市場開発動向とマーケティング チャネルを分析します。最後に、最新の投資プロジェクトの実現可能性が評価され、全体的な分析結果が提供されます。

製品に基づいて、このレポートには、主に次のように分割された各タイプの生産、収益、価格、市場シェア、および成長率が表示されます。
- PE
- LDPE
- PP
- PVC

エンド ユーザー/アプリケーションに基づいて、このレポートは、主要なアプリケーション/エンド ユーザーの状態と見通し、消費 (販売)、市場シェア、各アプリケーションの成長率に焦点を当てています。
- オートモーティブと交通
- 建設
- 光とサイネージ

このレポートを購入する前にお問い合わせください - https://www.industryresearch.biz/enquiry/pre-order-enquiry/17434250

地理的には、次の地域の消費、収益、市場シェア、成長率、履歴および予測 (2015-2025) の詳細な分析は、第 5-10 章で説明されています。
• 北米 (第 8 章で説明)
• ヨーロッパ (第 9 章で説明)
• アジア太平洋 (第 10 章で説明)
• 中東およびアフリカ (第 11 章で説明)
• 南アメリカ (第 12 章で説明)

重要ポイント:
• 正確な市場規模と予測データで潜在的な市場機会を理解する
• 保護フィルムを表面 業界の成長に焦点を当てた詳細な市場分析
• 保護フィルムを表面 市場の成長に影響を与える要因
• 支配的および純粋なプレイ ベンダーの詳細な競合分析
• 先進地域と発展途上地域の両方における 保護フィルムを表面 産業の予測分析
• 保護フィルムを表面 市場の主要セグメントに関連する重要な洞察
• 消費者の購買行動に影響を与える最新の市場動向分析

レポートのサンプル コピーを入手するには - https://www.industryresearch.biz/enquiry/request-sample/17434250

"
exiftools , hexedtior

<!--2023/10/12-->
[picoCTF][Forensics][information]

## Writeup
* exiftoolsでexif情報を確認
`exiftools cat.jpg`
![info.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/0f0ac278-6d8e-09f3-5332-0bd9fbc81f8e.png)
<br>

* CyberChefを使用して、Licenseの値をbase64でデコード。
![answer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/d8f579e8-b7d5-4b2f-fd6e-82997f02c700.png)

## 寄り道
* バイナリの確認
vimを使ったけど、うまく表示できない。
初期状態でバイナリエディタがあるみたい。
-nを付加しないと、色が見づらかった。(個人的な好み)
-rを付加して、読み込み専用にして、ファイルを確認。
~~~bash
hexeditor -n -r cat.jpg 
~~~
![hexeditor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/d7eb0a1a-1498-084a-470e-235d3b0eb6a5.png)
<br>

* 以上です。
java、SQLメモ

任意のテーブルにレコードを追加する
```java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            // データベースへの接続を確立
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "username", "password");
            
            // トランザクションの開始
            connection.setAutoCommit(false);

            // 動的なカラム名のリストを作成
            List<String> dynamicColumnNames = new ArrayList<>();
            dynamicColumnNames.add("column1");
            dynamicColumnNames.add("column2");
            dynamicColumnNames.add("column3");
            // ... 他のカラム名を追加

            // 動的なINSERT文のテンプレートを生成
            StringBuilder insertSQL = new StringBuilder("INSERT INTO mytable (");
            for (String columnName : dynamicColumnNames) {
                insertSQL.append(columnName).append(", ");
            }
            // カラム名のリストから余分なカンマを削除
            insertSQL.setLength(insertSQL.length() - 2);
            insertSQL.append(") VALUES (");
            for (int i = 0; i < dynamicColumnNames.size(); i++) {
                insertSQL.append("?, ");
            }
            // パラメータ用のプレースホルダーを追加
            insertSQL.setLength(insertSQL.length() - 2);
            insertSQL.append(")");

            preparedStatement = connection.prepareStatement(insertSQL.toString());

            // ダミーのデータを挿入するループ
            for (int i = 0; i < 100000; i++) {
                // 各カラムの値を設定
                for (int j = 0; j < dynamicColumnNames.size(); j++) {
                    preparedStatement.setString(j + 1, "value" + i); // パラメータインデックスは1から始まるため、j + 1
                }

                // バッチに追加
                preparedStatement.addBatch();
                
                // バッチサイズが一定数に達したら実行
                if (i % 1000 == 0) {
                    preparedStatement.executeBatch();
                }
            }

            // 残りのバッチを実行
            preparedStatement.executeBatch();

            // トランザクションのコミット
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            // エラーが発生した場合、トランザクションをロールバック
            try {
                if (connection != null) {
                    connection.rollback();
                }
            } catch (SQLException rollbackException) {
                rollbackException.printStackTrace();
            }
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException closeException) {
                closeException.printStackTrace();
            }
        }
    }
}
```
useRefとuseStateの違いは？ユースケースなど

`useRef` と `useState` は、React の Hooks の中で非常に一般的に使用されるものですが、それぞれ異なる目的と動作特性を持っています。以下に、それぞれの違いを概説します。

### `useState`

1. **目的**: コンポーネントの状態を保持・管理するために使用します。
2. **動作**:
    - `useState` は、初期値を受け取り、現在の状態値とその状態を更新する関数をペアで返します。
    - 状態の更新関数を呼び出すと、コンポーネントは再レンダリングされます。
3. **使用例**:
    ```javascript
    const [count, setCount] = useState(0);
    ```

### `useRef`

1. **目的**:
    - DOM 要素への参照を保持するため。
    - 任意の可変な値（re-render に影響を与えずに保持される）を保持するため。
2. **動作**:
    - `useRef` は、引数として与えられた初期値を持つ `ref` オブジェクトを返します。
    - `ref` オブジェクトの `current` プロパティを通じて、保持された値にアクセスすることができます。
    - `ref` オブジェクトの値（`current` プロパティの値）が変更されても、コンポーネントは再レンダリングされません。
3. **使用例**:
    ```javascript
    const inputRef = useRef(null);
    ```

### 主な違い

1. **再レンダリング**:
    - `useState` の状態が変更されると、コンポーネントは再レンダリングされます。
    - `useRef` の `current` 値が変更されても、コンポーネントは再レンダリングされません。
2. **用途**:
    - `useState` は、コンポーネントの状態の管理・変更を行うために使用されます。
    - `useRef` は、DOM 要素への参照や、再レンダリングを引き起こさない任意の値を保持するために使用されます。

この2つの Hook は異なる目的と動作特性を持っているため、必要に応じて適切なものを選択して使用することが重要です。

## useRefはどんなユースケースで使いますか？

`useRef` は多岐にわたるユースケースで使用されます。以下に、主な使用シナリオとその例を挙げます：

1. **DOM 要素への参照**:
    - 特定の DOM 要素に直接アクセスしたいときに使用します。
    - 例: インプットフィールドに自動的にフォーカスを当てる、DOM 要素のサイズや位置を取得するなど。

    ```javascript
    const inputRef = useRef(null);
    useEffect(() => {
      inputRef.current.focus();
    }, []);
    return <input ref={inputRef} />;
    ```

2. **以前の state や props の値の保持**:
    - コンポーネントの再レンダリングに影響を与えずに前の値を保持したい場合に使用します。
  
    ```javascript
    const count = useState(0);
    const prevCountRef = useRef();

    useEffect(() => {
      prevCountRef.current = count;
    }, [count]);

    // どこかで prevCountRef.current を使用して前の count 値にアクセスする
    ```

3. **外部ライブラリやインスタンスの保持**:
    - たとえば、外部ライブラリが生成するインスタンスや、タイマーの ID などを保持するために使用します。
  
    ```javascript
    const animationInstance = useRef(null);

    useEffect(() => {
      animationInstance.current = new SomeAnimationLibrary();
      return () => {
        animationInstance.current.destroy();
      };
    }, []);
    ```

4. **変更をトリガーしない変数の保持**:
    - コンポーネントの再レンダリングを引き起こさない変数を持つ場合に使用します。この変数はコンポーネントライフサイクル全体で生き続けます。
  
    ```javascript
    const renderCount = useRef(0);

    useEffect(() => {
      renderCount.current = renderCount.current + 1;
    });

    // どこかで renderCount.current を使用してレンダリングの回数にアクセスする
    ```

5. **コールバック関数内での安定した参照**:
    - 頻繁に変更される可能性があるコールバック内で、安定した参照を持つ必要がある場合に使用します。

    ```javascript
    const callbackRef = useRef(callback);

    useEffect(() => {
      callbackRef.current = callback;
    }, [callback]);

    useEffect(() => {
      const interval = setInterval(() => {
        callbackRef.current();
      }, 1000);
      return () => clearInterval(interval);
    }, []);
    ```

これらの例は `useRef` の一般的なユースケースの一部です。実際には、さまざまな状況や要件に応じて、このフックを使用して多くのことを実現することができます。