OmniAICreator/Qiita-1.07M huggingface dataset:
AtCoder Beginner Contest 343参戦記録

RubyでAtCoderに参戦した記録です。
初めてABC3完できました！（配点は低めでしたが…）
D問題はコンテスト終了後に解説を見てからコードを書きました。

## [ABC343 A Wrong Answer](https://atcoder.jp/contests/abc343/tasks/abc343_a)
0~9の整数のうち、与えられた整数A、Bの和と等しくないもののうち1つを出力する問題です。
```Ruby
a,b=gets.split(" ").map(&:to_i)
for i in (0..9)
  if i != a + b
    puts i
    break
  end
end
```

## [ABC343 B Adjacency Matrix](https://atcoder.jp/contests/abc343/tasks/abc343_b)
N個の頂点があるグラフについて、各頂点が他のどの頂点と辺を持っているかを出力する問題です。

```Ruby
n = gets.to_i
array = []
n.times do
	array << gets.split(" ").map(&:to_i)
end

array.each do |e|
  ans = []
  e.each_with_index do |g, i|
    if g == 1
      ans << i + 1
    end
  end
  puts ans.join(" ")
end
```
0と1で表される行列が与えられ、各行が各頂点についての情報となります。各行の値が1の時のインデックス+1が、その頂点と辺がつながっている頂点の数値です。

## [ABC343 C 343](https://atcoder.jp/contests/abc343/tasks/abc343_c)
与えられる正整数Nの回文立方数の最大値を求めます。
ここでの回文立方数とは、何らかの正整数の3乗で表され、先頭に0を付けずに10進数表記したとき、数字が回文になっているものと定義されています。
```Ruby
n = gets.to_i
i = 1
while i * i * i <= n
  if (i*i*i).to_s == (i*i*i).to_s.reverse
    ans = i
  end
  i += 1
end
puts ans ** 3
```
Nは10**18以下ということで、1~Nまで全て調べるとTLEになってしまいます。
ここで回文立方数は何かの整数の3乗ということで、Nの三乗根までを調べればよいということになります。
回文判定は、数値をto_sメソッドでStringとし、reverseしたものと同値であるかで判定しました。
条件を満たすiのうちの最大のものがansに格納されるので、その3乗を出力します。

## [ABC343 D 343](https://atcoder.jp/contests/abc343/tasks/abc343_d)
N人が参加するコンテストにおいて、1秒ごとに誰が何点獲得したかのデータが与えられます。各秒において、何種類の得点の値が現れるかを出力する問題です。
こちらも各秒ごとにN人全員の得点を調べているとTLEになってしまいます。

Hashのキーを得点、値を選手の番号の配列にすることも考えましたが、次にその選手が得点したときにHashからその選手の現在の得点を探すのに手がかかりやはりTLE、ということで時間内の回答はできませんでした。

### 解決策：各選手のその時点の得点を格納する配列と、各得点保持者が何人いるかを格納するハッシュを用意する
AtCoderのYouTube解説放送をみて、そうか、各人の得点を別の配列で管理しておけば、ハッシュではその得点の人が何人いるかという人数だけ増減させればいいのか、と気づかされました。。
```Ruby
n,t=gets.split(" ").map(&:to_i)
array = []
t.times do
	array << gets.split(" ").map(&:to_i)
end

member = Array.new(n){0}
hash = {0=>n}  # 最初は0点がn人
hash.default = 0  
array.each do |a,b|
    hash[member[a-1]] -= 1  # 最初は全員0点から始まるので、member[a-1]==0、つまりhash[0](=>n)を参照するので、1を引いてもマイナスにはならない
    hash.delete(member[a-1]) if hash[member[a-1]] == 0  # その得点の人が0人になったらHashから削除
    member[a-1] += b
    hash[member[a-1]] += 1  # 上でHashのdefault値を設定することで、ここでのエラーを防ぐ(nilクラスへのNoMethodError)
    puts hash.size
end
```
## おわりに
今回は配点が低めだったとはいえ、初めてC問題で得点出来て素直にうれしかったです。
D問題も手が届かないような技術を使っているわけではなかったので、解説を見て悔しさがありました。。引き続き精進していきます。
pythonのconfigparserを用いてconfig.iniからListを読み込みたい

### configparserの基本的な使い方
素晴らしい記事があるのでこちらを参照ください。
- [pythonプログラムにおける設定ファイル管理モジュール](pythonプログラムにおける設定ファイル管理モジュール～configparserの使い方と注意点～)
### 問題点
- 設定ファイル（config.ini）にリストを記述してリストとして読み込みたいが、configparserは文字列として読み込んでしまう。
### 解決方法
- eval関数を利用して、式として評価してあげる。

### サンプルコード
例えば特定のフォルダ内にある、複数の拡張子を扱いたい場合のことを考えます。
`config.ini`
- DEFAULTの部分は任意の変数名に書き換えれます。
```
[DEFAULT]
EXTENSION_TYPES = [
    ".zip",
    ".log",
    ".png"
    ]
```
`example.py`
- configparserを利用してconfigを読み出します.
- eval関数を利用して文字列をリストとして評価します.
```Python
config = configparser.ConfigParser()
config.read(config_path, encoding="utf8")

extension_types=eval(
            config["DEFAULT"]["EXTENSION_TYPES"])
```

### 改善点
- 　confgparserに詳しくないとeval関数で何をやっているのか分かりづらい。
- 　そのため、eval()でやっていることを`convert_str_to_list`などの名前に変えてラッパーを実装してあげるとより丁寧かも。
SQLSTATE[HY000] [1045] Access denied for user 'root'@'172.21.0.2' ...原因調査


# MySQLへの接続が拒否に関するエラー
appコンテナとdbコンテナの接続において、
`php artisan migrate`コマンドを実行したところ下記のエラーが出た。
```
root@a0aefa03324d:/app/laravel# php artisan migrate

   Illuminate\Database\QueryException 

  SQLSTATE[HY000] [1045] Access denied for user 'root'@'172.21.0.2' (using password: YES) (SQL: select * from information_schema.tables where table_schema = database and table_name = migrations and table_type = 'BASE TABLE')
```
`access denied...`どうやらmysqlへの接続が拒否されているようだ。
docker-compose.ymlファイルと.envファイルの環境変数を確認してみる。
```docker-compose.yml
  db:
    build:
      context: .
      dockerfile: ./docker/db/Dockerfile
    ports:
      - 3306:3306
    environment:
      MYSQL_DATABASE: MYSQL_DATABASE
      MYSQL_USER: user
      MYSQL_PASSWORD: password 
      MYSQL_ROOT_PASSWORD: password 
      TZ: 'Asia/Tokyo'
    volumes:
      - mysql-volume:/var/lib/mysql
```

```.env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=database
DB_USERNAME=root
DB_PASSWORD=password
```
database名とユーザー名が異なっているのでここが原因そう。
.envファイルを下記に修正して再度`php artisan migrate`コマンドを実行してみる。

```.env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
// 修正
DB_DATABASE=MYSQL_DATABASE
// 修正
DB_USERNAME=user
DB_PASSWORD=password
```

`php artisan migrate`コマンド実行。
```
root@a0aefa03324d:/app/laravel# php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (45.90ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (28.35ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (16.78ms)
Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated:  2019_12_14_000001_create_personal_access_tokens_table (41.32ms)
```
うまくいきましたね。
JupyterHubでTerminalのShellをBashにする

# 問題概要
Ubuntuのシステムに以下を参考にJupyterHub環境を構築した。便利に使用しているが、Terminalを起動するとShellがShとなってしまい、慣れたBashでないため使いづらく感じていた。

# 背景情報
JupyterHubを使用するユーザーのログインShellはBashである。JupyterHubを起動するプロセスのユーザーのログインShellをBashにしても、各ユーザーのJupyterHubで起動するTerminalではShとなってしまう。

# 解決策の概要
JupyterHubを起動するプロセスの環境変数SHELLでどのShellを起動するか振り分けていることがわかったため、systemctlで起動する際に以下のようにserviceファイルに記載する。

```sh:jupyterhub.service
[Service]
Environment="SHELL=/bin/bash"
```

# 手順
1\. JupyterHubを停止
 ```bash:bash
 $ sudo systemctl stop jupyterhub.service
 ```
2\. Serviceファイルを書き換え
3\. Serviceファイルをリロード
 ```bash:bash
 $ sudo systemctl reload daemon-reload
 ```
4\. JupyterHubを実行
 ```bash:bash
 $ sudo systemctl start jupyterhub.service
 ```
# 結果
各ユーザーでBashが起動しました。

# 注意事項
すべてのユーザに波及するため、Shを使用したい人にもBashを強制してしまいますが、ログイン後に各自シェルを変えてもらうことに。
PDFファイルを圧縮したかった（メモ）

[こちら](https://dev.classmethod.jp/articles/azure-ad-terms-of-use/)の機能の検証をしていたところ、Entra IDの制限で2MBまでのPDFしか利用できないことがわかり、利用していた利用規約PDFが2MBを超えていたため圧縮する必要があった。

VSCodeのMarkdown PDFを使用したものだったが、画像の圧縮オプション（markdown-pdf.quality）はあるもの、全体のファイルを圧縮するためのオプションが見当たらなかったので、別の方法で当たることにした。

## 早速ChatGPTに聞いてみた

早速ChatGPTに聞いてみたところ、以下の３つの方法を示唆された

1. Ghostscriptを使用する
1. pdftk
1. pdfcompress

PDFKitは、ファイルの分割などはできるようだが圧縮機能は持たず、今回の用途には不向きと判断。
Ghostscriptとpdfcompressは好みが分かれると思うが、圧縮だけとはいえ今後も使う可能性があると判断しGhostscriptを使用した

## 試した結果

PCの環境を汚したくなかったので、Dockerを使う。

```bash
$ docker run --it --rm $(pwd):/app alpine:latest ash
/app # apk update
/app # apk add ghostscript
/app # gs --version
10.02.1
```

これで、Ghostscript自体はインストールできた。
aptなどのリポジトリにも含まれているらしく簡単に入手できるのはありがたい。

次に、コマンドを指定してファイルを変換する

```bash
s -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/ebook  -dNOPAUSE -dQUIET
 -dBATCH -sOutputFile=output.pdf ./terms_of_service_ja-jp.pdf
```

この時、品質に影響するオプションは「PDFSETTINGS」

| オプション値 | 品質 |
| :- | :- |
| /screen | 最も低い解像度と画質で、ファイルサイズを最も小さくします。 |
| /ebook | 良好な品質と中程度のファイルサイズを提供します。 |
| /printer | 高品質（プリント適用）で、より大きなファイルサイズになります。 |
| /prepress | 高品質で、画像を元の品質で保持し、ファイルサイズがさらに大きくなります。 |

最初、`/ebook`で試したのだが、埋め込んでいた画像がかなり荒くなってしまった。
そのため`/printer`にしたところまぁ見れるかなという画像になったのでこれで行こうと思う。

結果：
* 4235628バイト -> 336930バイト
* 3959783バイト -> 117805バイト
Embed a CRM Analytics Dashboard in Lightning Experience


# Embed a CRM Analytics dashboard on a home page

https://trailhead.salesforce.com/content/learn/projects/embed-an-einstein-analytics-dashboard-in-lightning-experience/embed-an-analytics-dashboard-in-a-home-page


+ [【未解決】We can't find the Sales home page. Make sure that you’re using your CRM Analytics-enabled Developer Edition org and that you’re in the Sales app.](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000Jy0Yl)

+ [ We can't find the Sales home page. Make sure that you’re using your CRM Analytics-enabled Developer Edition org and that you’re in the Sales app.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007XITMC)

言語設定が英語の必要があるみたいです。

他の回答では

:::note
I was able to pass by going into the Service Cloud Console and editing the Home page there calling it sales.

Service Cloud コンソールに移動し、そこで sales という名前のホームページを編集することで、合格することができました。
:::
タイムスタンプから日付だけを抽出する(SPSS Modeler データ加工逆引き1-19)

# タイムスタンプから日付だけを抽出する

![スクリーンショット 2024-03-04 10.22.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b869ed02-915c-dc9d-bf52-4c152f61ff9a.png)

## 1.想定される利用目的

・集計/観察の粒度を秒から日に変更する

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/main/timestamp_date.str

## 3.サンプルストリームの説明

![スクリーンショット 2024-03-04 10.23.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/213d13b4-6b97-8145-7d03-454797c08fde.png)

a.入力するデータは以下の通りです。
![スクリーンショット 2024-03-04 10.24.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/0766f097-6337-1cb3-fe86-c5b48844b252.png)

#### タイムスタンプ型から日付型へ

b.[フィールド作成]ノードを編集します。シンブルな型変換で秒以下がなくなります。
![スクリーンショット 2024-03-04 10.25.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/bbdb22ae-0b3e-4ec8-c0c9-6c02109e14ba.png)

[プレビュー]します。
![スクリーンショット 2024-03-04 10.33.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2938e512-2d7a-aafc-bbb2-60989f01259f.png)

#### 文字列型から日付型へ

c.[フィールド作成]ノードを編集します。先頭文字列N文字を残す関数startstringを利用します。

![スクリーンショット 2024-03-04 10.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/0a4c2c42-d17c-878a-08ce-433bedc0a90f.png)

[プレビュー]します。

![スクリーンショット 2024-03-04 10.25.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/78fbca37-9f81-7c82-e59a-f7810953a2c3.png)

#### 注意事項

時間に関するフィールドは計算の有無や扱いやすさで文字列か日付型かを選択します。

## 4.参考情報

#### タイムスタンプの差の計算

https://qiita.com/kawada2017/items/8e1291801aacf5427e7d

#### よく使う「日付と時間」関数

https://qiita.com/Makimaki2020/items/72e3b774039327fa4ac4

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
Unexpected close tag


+ [Unexpected close tag while deploying](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007YwClf)

```Xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
  <types>
         <members>Knowledge__kav.Value_Q&A</members>
          <name>RecordType</name>
   </types> 
<version>58.0</version>
</package>
```

問題なさそうですが、１つ　＆　があるのが注意。

:::note
Replace & with the escape code

 
```
　& --> &amp;
 ```
 :::

 The (&) is an XML special character, if you use it, you will get that error. 

to work around this, they made something called HTML or XML entities, they are  a piece of text ("string") that begins with an ampersand ( & ) and ends with a semicolon ( ; )

XML entities are special codes used to represent reserved characters and symbols in XML
Vim初心者が知っておきたい基本操作についてまとめてみた

## はじめに
この記事では、Vim初心者が抑えておきたい基本操作について簡単にまとめてみました!これからVimを学ぼうとしている初心者の皆様に少しでもお役に立てることができれば幸いです。では、始めていきます！

## Vimってそもそも何？
Vimとはviという世界で最も利用されているテキストエディタの拡張版です。独自のコマンドやモードの切り替え機能を搭載することにより高速で編集できることが大きな魅力になっています。

## Vimのモードについて
Vimには四つのモードがあります。これらのモードを駆使しながら、操作していきます。以下に各モードの名前とその内容をまとめました。

| モード | 内容|起動|
|:-:|:-:| :-: |
|   ノーマルモード|  Vim起動時の最初のモードです。このモードを起点に各モードに遷移できます。escボタンを押すことによって、ノーマルモードに遷移できます。 |esc|
| 入力モード  |   iやaなどのボタンを押すことによって入力モードに遷移することができます。ファイル編集や文字入力をする際に使用。|i/aなど|
|  ビジュアルモード |  vを押すことによってビジュアルモードに入ることができます。主に範囲選択したい時に利用します。|v|
|  コマンドモード | :や/を入力することで、コマンドモードに移行することができます。変更内容の保存やVimを終了させる際などに利用します。|:|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087476/e6b0ac21-fefd-1dab-16a6-4e0e883e73c4.png)

引用:https://zenn.dev/mo_ri_regen/articles/vim-four-modes




## ノーマルモードのコマンド

### 移動系コマンド

| コマンド | 動作内容|
|:-:|:-:|
|  h |  左に移動 |
|   j|   下に移動|
|  k |  上に移動|
|  l |   右に移動|
|H|ページ内の一番上に移動|
|M|ページ内の真ん中に移動|
|L|ページ内の一番下に移動|
|w|カーソルの次にある単語内の先頭に移動|
|b|カーソルの後ろにある単語内の先頭に移動|
|e|カーソルの次にある単語内の末尾に移動|
|数字+w,b,e|数字の分だけ移動させることができる|
|  gg |  ページの一番上にいく |
|  G |  ページの一番下にいく |
|$|カーソルのある行の末尾に移動|
|^|カーソルのある行の先頭に移動|
|0|　そのページ内の行頭へ移動|


### 削除系コマンド

| コマンド| 動作内容|
|:-:|:-:|
| x|  一単語削除 |
| 数字+x　| 数字の数だけ削除  |
|dd|カーソルのある行を全削除|
|d$|カーソルのある箇所から末尾まで削除|
|dw|単語を一つ消す|
|D|カーソルから右にある行を全削除|


### その他

| コマンド| 動作内容 |
|:-:|:-:|
|  y |  コピー |
|　yy | 一列コピー　|
|  p |  ペースト |
| u| 直前の操作を取り消す  |
|Ctrl+r|取り消しの取り消し|
|J|カーソルがある行に一つ下の行を連結|


## 入力モード（Insertmode）

| コマンド| 動作内容|
|:-:|:-:|
|  i |  カーソルのある場所でインサートモードに入る |
|  a |カーソルの隣でインサートモードに入る  |
|  A | カーソルのある行の最後に移動して、インサートモードに入る  |
|  I | カーソルのある行の先頭に移動して、インサートモードに入る  |
| .　| 直前の入力内容を繰り返す  |
| ciw | カーソルの下にある単語を消し、インサートモードに入る  |
|S|カーソルのある行を全て消して、インサートモードに入る|

## ビジュアルモード

| コマンド| 動作内容 |
|:-:|:-:|
| v + 移動キー  | 移動キーの分だけ範囲選択をすることができる  |
|  v + 移動キー + y | 範囲選択した部分をコピーする  |
|  v + 移動キー　+ d | 範囲選択した部分を削除  |
|  c | 選択した範囲を消し、インサートモードに入る |

## コマンドモード

| コマンド| 動作内容 |
|:-:|:-:|
| :w  |  保存 |
| :w ファイル名　 | 指定したファイルに変更内容を保存  |
|  :wq | 保存して終了  |
|  :q | 終了  |
|   :q!　|  保存せずに強制的に終了 |
| :!ls / :!dir  | ディレクトリ一覧を表示  |

## 終わりに
以上でVimの基本操作に関する紹介は終わりです。このブログはあくまで参考程度に留めて、実際に触って見ることをお勧めします!そうした方が何倍も早く覚えることができると思います!このブログを読んだ皆さんにはvimtutorをぜひやってみてください!３周もすれば、Vimの基本操作についてある程度理解することができるのではないかと思います! 以下にvimtutorの始め方を紹介しているリンクも貼っておきます!

https://qiita.com/y-temp4/items/3032d22cb5cc6ae3117a

その他参考文献

https://qiita.com/JpnLavender/items/fabcc79b4ab0d52e1f6d

https://dev.classmethod.jp/articles/vim-quickstart-with-vimtutor/

https://qiita.com/Hiyajo/items/9f87c5687652da42f275
STM32C011でサーボのパルスを測って遊ぶ(STM32C011J4M7)


x ラジコンサーボを繋ぐ時は、カプラ等の安全対策をしてください。(パソコンが壊れます)

目的
pulseInがあるので遊ぶ

結果

![o_cop981.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d22f1e54-d624-b8fb-14ea-3aa374512de1.jpeg)


![o_cop980.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e31e9fd2-3ad7-3cec-fef3-1921046c8216.jpeg)


受信

```c++


//GPIO_pulseIn_C011_1


//初期化
void setup() {

  delay(3000); //do not delete

  //シリアルの初期化
  Serial.setTx(PA8);
  Serial.setHalfDuplex();
  Serial.begin(9600);

  pinMode(PA12, INPUT);//pulseInのピン

} //setup


//1 PB7 (14)
//2
//3
//4 
//
//8 PA14 (12)
//7 PA13 (11)
//6 PA12 (10)
//5 PA8  (8)

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

  //サーボパルスの読み取り
  unsigned long duration; //読み取り値
  duration = pulseIn( PA12 , HIGH , 40000); //C011 PA12

  //パルスの長さをusで出力
  Serial.printf("%8d us\r\n",(int)duration);

  delay(1000);//1秒待つ
  
} //loop


```

PWM

```c++


//PWM_servo_test22_C011_1


//インクルド
#include <Arduino.h>


//定義
//1000の割り算 だいたい正しい。
#define DIV1000(n) ((n+((n*25)>>10))>>10)

//data SG90
// 2400us 2.4ms
#define s_max  2400
// 500us 0.5ms
#define s_min  500
#define s_r    (2400-500)
#define s_c    (65536/20000)*1000

//#define SN(n6)  (n6*((65536/20000)*1000))
//↓式変形と要約↓6万を2万で割ると3ぐらい、3を1000倍するとだいたい3000
#define SN(n6)    (n6*3277)

#define DD PA8    // potentiometer connected to analog pin x


//初期化
void setup() {

  pinMode(DD, OUTPUT);   // sets the LED pin as output
  analogWriteFrequency(50);   //周波数
  analogWriteResolution(16);  //分解能

}//setup


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

  int ii; //ループカウンター

  //for (ii = 500; ii < 2400; ii=ii+100) {

  ii = 1450;
  analogWrite(DD, DIV1000(SN(ii))  );   // analogRead values go from 0
  // to 4095, pwmWrite values
  // from 0 to 65535, so scale rough
  delay(1000); //1000mS

  //}//for

}//loop

```
Next.js & jest & ESM & Vanilla-extractで詰まったところ

Next.js & jestのプロジェクトにvanilla-extract & esm形式のライブラリを採用しました。
その際にunit testで引っかかった問題の備忘録です。

# 環境
Next.js: 14.1.0
jest: 29.1.2
node: 21.4.0
environment: jest-environment-jsdom

# esm対応
エラー内容
```
    ./node_modules/some-library/components/button/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { Button } from './button';
                                                                                      ^^^^^^
 
    SyntaxError: Unexpected token 'export'
```
https://jestjs.io/ja/docs/ecmascript-modules
jestはesmを実験的サポートしているものの、node_modules配下はトランスパイルされないので
transformIgnorePatternsに対象のライブラリ(foo-library)を追加する必要あり。

ただし普通に設定してもnext/jestはその設定を上書きしてしまうので、nextJest後に無理やり置き換える。
また、node_modulesに適用させるためbabelの設定ファイルを.babelrcではなく.babel.config.jsに変更する必要がある。
```
import nextJest from 'next/jest';

const createJestConfig = nextJest({
  dir: './',
});

/** @type {import('@jest/types').Config.InitialOptions} */
const customJestConfig: Config = {
  // 省略
};

module.exports = async () => ({
  ...(await createJestConfig(customJestConfig)()),
  transformIgnorePatterns: [
    'node_modules/(?!(foo-library)/)',
  ],
});
```

# vanilla-extract対応
エラー内容
```
   Styles were unable to be assigned to a file. This is generally caused by one of the following:
 
    - You may have created styles outside of a '.css.ts' context
    - You may have incorrect configuration. See https://vanilla-extract.style/documentation/getting-started
 
      at Object.getFileScope (node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.cjs.dev.js:35:11)
```
https://vanilla-extract.style/documentation/integrations/next/
公式の設定手順を試すも反映されず。

https://vanilla-extract.style/documentation/test-environments/#remove-style-mocking
追加でmoduleNameWrappersからcssへのstyleMock.jsの設定を削除。

ただし、こちらもesm同様にnext/jestに上書きされてしまったので最後に上書き。
また、その際に自プロジェクトのcss(my-css-folder)のみは従来通りのstyleMock.jsを適用するよう設定。

```
import nextJest from 'next/jest';

const createJestConfig = nextJest({
  dir: './',
});

/** @type {import('@jest/types').Config.InitialOptions} */
const customJestConfig: Config = {
  // 省略
};

module.exports = async () => {
  const config = await createJestConfig(customJestConfig)();

  if (config.moduleNameMapper) {
    const backupModuleNameMapper = config.moduleNameMapper['^.+\\.(css|sass|scss)$'];
    delete config.moduleNameMapper['^.+\\.(css|sass|scss)$'];
    config.moduleNameMapper['my-css-folder/.+\\.css$'] = backupModuleNameMapper;
  }
  config.transform = {
    '\\.css\\.[tj]s$': '@vanilla-extract/jest-transform',
    ...config.transform
  };
  return config;
};
```

以上で動作は確認できました。
ただ何分強引なやり方なのでもう少しスマートな対応も模索していきたいと思います。
Raspberry Pi 5 でmakeに失敗する際の対処法

# 環境
raspberry pi 5
Ubuntu Desktop 23.10 (Raspberry Pi ImagerでSDカードに書き込み)

# 症状
make 実行時に
```
make[1]: *** /lib/modules/6.5.0-1011-raspi/build No such file or directory. Stop.
```
と実行が止まってしまう。

# 対策
下記をインストール。
```
sudo apt install build-essential module-assistant
```
下記を実行。
```
sudo m-a prepare
```
No such file or directoryが消え、makeが通るようになっているはず。

# 参考
https://linux.just4fun.biz/?Debian/build%EF%BC%9A%E3%81%9D%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%84%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93
Ruby on Rails: 営業日時の処理・表示に関する一般的な問題とその解決策

# 問題1

Ruby on Railsの開発において、日付や時刻の扱いはよく遭遇する課題です。特に、日付や時刻を扱うアプリケーションでは、文字列と`String`、`Date`、`DateTime`、`Time`オブジェクト間の変換が必要になる場合が多々あります。不適切な変換やフォーマットのミスマッチは、期待しない動作やエラーの原因となり得ます。

この記事では、具体的なエラーの事例を取り上げつつ、その原因と解決策について解説します。

## 事例と問題点

Railsアプリケーションにおいて、ユーザーからの入力を基にサービスの提供可能性を判断する機能を実装している際、以下のような`TypeError`が発生しました。

```
TypeError: no implicit conversion of ActiveSupport::Duration into String
```

このエラーは、文字列型の時刻データに対して`ActiveSupport::Duration`オブジェクトを加算しようとしたときに発生します。原因は、時刻を表す文字列（例: `"09:00"`）に、`ActiveSupport::Duration`（例: `60.minutes`）を加算しようとしたためです。Rubyでは、文字列に対して直接時間を加算することはできません。

## 問題の解決

問題の解決には、文字列型の時刻データを適切な`Time`オブジェクトに使用する必要がありました。具体的には、以下のコード変更により問題が解決しました。

```ruby
# Before
# available_start_timesはTime型
<% available_start_times = calculate_available_start_times(@date, @company, total_duration) %>
 <%= form.select :start_time, available_start_times.map { |time| [time.strftime("%H:%M"), time] }, { include_blank: true }, { required: true } %>
```
```ruby
# After
# available_start_timesはTime型
<% available_start_times = calculate_available_start_times(@date, @company, total_duration) %>
<%= form.select :start_time, @available_start_times.map { |time| [time, time] }, { include_blank: true }, { required: true } %>
```

変更後のコードでは、`Time`オブジェクトを`Time`オブジェクトとしてマッピングしています。

# 問題2

以下はRailsアプリで、サービスの提供可能性を判断し表示する機能を実装中に遭遇した問題です。
`schedules`の`for_customer_index`アクションではサービス提供可能性が正しく`○`、`△`、`×`として表示されるのに対し、`reservations`の`confirm`アクションでの表示が全て`×`になるというものでした。

## 原因

この問題の原因は、`@date`変数が適切に`Date`オブジェクトとして扱われていなかったことにありました。具体的には、`confirm`アクション内で`@date`を設定する際に、単に文字列として代入していました。

```ruby
# Before
@date = params[:reservation][:date]
```

この状態では、`@date`が文字列として扱われ、後続の処理（特に日付の比較や時間の計算）で期待通りの挙動を示さなかったため、サービス提供可能性の判定ロジックが誤った結果を返していました。

## 解決策

問題の解決には、`@date`に`Date.parse`を使用して、文字列から`Date`オブジェクトへと変換する処理を加えました。これにより、日付として正しく扱うことができるようになり、サービス提供可能性の判定が正確に行われるようになりました。

```ruby
# After
@date = params[:reservation][:date].present? ? Date.parse(params[:reservation][:date]) : Date.today
```

この変更により、`confirm`アクション内でも`for_customer_index`アクションと同様に、サービス提供可能性が正しく`○`、`△`、`×`として表示されるようになりました。

# 解決策のポイント
**型の確認と変換**：日付や時刻を扱う際には、適切なデータ型を使用することが重要です。特に、文字列と`Date`/`DateTime`/`Time`オブジェクト間での変換が必要な場合は、明示的な変換メソッド（例: `Date.parse`）を利用して型を一致させましょう。
GPTsで貸借対照表PDFを表形式に変換してみた。

<h1>経緯</h1>
<div>
アサインされたプロジェクトの一環でPDFの決算書を自動でデータ化する必要性が出てきた。
本来であればAI-OCR、もしくはIDPのようなSaaSを利用してどうこうすればとりあえずはどうにかなる話ではあった。
しかし、クライアントの意向を深ぼって行く内に、「安く簡単になんとかならないか、そしてAIをうまく活用した事例として外部にPRしたい。」といった内なる要望にたどり着き、GPTを使って何とかしてみようとプロジェクト内で決定し、GPTを利用したPDFのデータ化に取り組み始めた。
</div>

<h1>結論</h1>
結果として現状テキストPDFの表形式変換GPTsを作成することができた。
現GPTには画像を日本語OCRすることはできず、PDFにテキスト情報があるもののみ変換を行えた。<br>
参考文献：<a href="https://qiita.com/sakasegawa/items/8abd902ac45a3cd2862c">OpenAIのAPIを使って任意の画像やPDFからいい感じに情報抽出する方法</a>

<h2>成果物</h2>
<a href="https://chat.openai.com/g/g-wcPiIvyuM-bsbiao-chu-li">BS表出力</a>
テキスト形式の貸借対照表PDFを添付し、説明にあるプロンプトを入力すると、科目と金額のみを抽出することができる。
複数年度表を読み込ませた場合は科目で結合し年度分の金額が横並びになり比較できるようにする出力としている。

<h2>苦労した点</h2>
<h3>読み取り精度が安定しない</h3>
<div>一般的な貸借対照表の形式はシンプルな表形式ではなく、左に資産、右に負債と純心さんといったように会計的な観点での表形式になっており<br>そのまま読み込ませても科目と金額が一致したり、しなかったりと安定性に欠けていた。</div>
<div>何度か試し、エラーを確認していく内にわかったのだが
<ul>
<li>GPT内でのPDFの扱い方はLLM的な観点で読み込む。</li>
<li>pythonのPDFライブラリを使って読み込む、</li>
</ul>
2種類の読み込み形式があるようで、かつ、pythonの場合ライブラリの選択が何通りかあるようだった。
貸借対照表の読み込みの場合は、ライブラリのcamelotを利用して、PDFを読み込み、その読み込みデータをGPTに理解させるやり方が一番安定していたので、その旨をcustom introductionに記載した。</div>

<h3>表を結合させる時、エラーでタイムアウトしてしまう。</h3>
<div>
データの結合において、GPTはpythonのpandasを使って結合したがるが、GPTで扱えるセッションデータ量には限りがある。
今回表データの結合では3つ以上の表を結合する必要があり、セッションタイムアウトが頻発していた。
しかし実はpythonを使わず、LLMの処理で結合させることができ、「pythonは使わず、手動で」といつプロンプトを加えることで解決した。
</div>
<h3>複雑なプロンプトを一度に行うと、指示の無視が頻繁に発生する。</h3>
<div>はじめ、複数年度分の貸借対照表PDFを一度に添付し、結合までのプロンプトを全て記載し一気に処理をさせようとした</div>
<div>すると、指定ライブラリの指示や結合の指示、データの抽出などにおいて一気に不安定になってしまった。</div>
<div>単年度分のPDFを順に処理をさせ、chat上に出力された表を結合させることで出力の安定化を図ることができた。</div>

<h2>今後の展望</h2>
<div>最終的には画像形式、テキスト形式問わず、貸借対照表のPDFは指定の表形式にすることを目標としている。
画像形式のPDFは外部OCRで出力させたデータをGPTで構造化が可能ではと思っている。
全体の自動化にはIPaasのmakeを利用するか
GPTのAPIを使ったアーキテクチャを検討している。
参考文献：<a href="https://qiita.com/watanabe-tsubasa/items/12dc7ba9a6de55e8afd9">GPTが人知れず既存の名刺管理アプリを抹殺していた話</a>
</div>
昨日使えていたLinuxコマンド（rbenv）が急に使えなくなった話

レアケースだとは思いますが、誰かのために残しておきます。（４時間くらいハマった。。。。）




**状況**：初学者です。ruby on railsの環境構築をするにあたって、昨日使えていたrbenvコマンドが朝起きたら使えなくなっていた。（-bash: brew: command not found）
rbenvのパスは/.bash_profileで通っている。実行ファイルもある。



**結論**：/.bash_profile内のbrewのパスを自分で消していた。（寝る前にvimでいじっていた。。。）
brewの配下にrbenvがあったためrbenvコマンドを使えなくなった。



**解決方法**：Homebrewのbrewのパスを通した。そしたらrbenvも使えるようになった。
注意
・USERNAMEは自分の名前に変えてください。
・事前にhomebrewの格納場所を念のため確認しておきましょう。
・色々調べていると、(/opt/homebrew/bin/brew shellenv)のパスで通している人もいましたが、自分はshellenvってのがよくわからなかったのでやってません。


    echo 'export PATH="$PATH:/opt/homebrew/bin/"'>>/Users/USERNAME/.bash_profile



**感想**
多くのruby on rails 環境構築指南サイトはhomebrewをインストールした後にrbenvを入れさせるので、brewのパスが通った後にbrewのパスを消すことを想定していない。（そりゃそうだ。）
１からパスの意味や、SHELLとは何かを調べていい勉強になった。



**初学者向けTIPS**
SHELL : CPUに命令を出すもの。macにはbashとzshがある。上記ではbashを使っています。
        自分が使っているshellの調べ方

    $echo $SHELL

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724172/f2c3276e-e6f0-a66e-ee1d-b61a81b377e1.png)



以上
「信じる」と「疑う」は逆のことか？

# 1.はじめに
どうも、ARIの名古屋支社に勤務している愛知県民こと、
新藏（にいくら）と申します♪
9月から引き続き、課題は色々ありますが課長代理で頑張っています。
(/・ω・)/

最近、以下2つの業務がありました。
- **人事考課で自己申告いただいた評価のエビデンスを確認する**
- **週次で案件状況を報告してもらい、発表を聞く**

上記の業務の中で、「人事考課の自己申告を疑われている」
「案件状況に問題があると疑われている」と感じるメンバもいる気がしました。

そこで
**人事考課では自己申告を信じ、案件に問題がないと信じて週次の報告は不要とする、**
という対応を思いついたのですが、それが適切かどうかが気になり、
**「信じる」と「疑う」が逆のことかを考えてみました。**

「信じる」と「疑う」の関係性について気になる方、
同じような悩みを持っている方、若手の方の参考になれば幸いです。
(*^^)v

# 2.他の方の「信じる」と「疑う」に関する意見

## 2.1.ChatGPTの意見
まずはChatGPTに、「信じる」と「疑う」について意見を聞いてみました。
要約すると以下となります。

:::note info
**一般的には「信じる」と「疑う」は逆のこと。
ただし、「信じるためには疑う」という言葉もある。**
:::

>「信じる」（Believe）と「疑う」（Doubt）は一般的に逆の意味を持つ言葉です。
>
>「信じる」は、あることや情報に対して信頼し、肯定的な態度を持つことを指します。
>これは信仰、信頼、確信、期待などを含みます。

>一方で、「疑う」は、あることや情報に対して疑問や不信感を抱くことを指します。
>これは不信、疑念、疑惑、懐疑的な態度などを含みます。

>「信じるためには疑う」という考え方は一般的にあります。
>このアプローチは、情報を受け入れる前に慎重に検討し、
>検証することが重要であるという立場を反映しています。

## 2.2.七海千秋さんの意見（ダンガンロンパ2）
ダンガンロンパ2でも、本記事のテーマに関する名言があります。
要約すると以下となります。

:::note info
**「信じる」と「疑う」は反対の意味ではない。
信じたいから疑う。**
:::

>あのね…「信じる事」と「疑う事」って、きっと反対の意味じゃないと思うんだ。
>疑いもするけど…それでも信じたい。その先にあるのが「信じる」って気持ちなんだよ。

>だって…疑う余地のないハッキリしている事なら、信じる必要だってないでしょ？
>誰かを信じる為にはね…「疑う」って事を乗り越えなきゃいけないんだよ。
>「疑う」を放棄した「信じる」なんて…そんなのただの噓っぱちだよ。

引用
http://phoenix-wind.com/ranking/vote/vote_danganronpa.php?word=%E7%96%91%E3%81%84

## 2.3.ぶんようさんの意見
「お気楽論」という書籍を執筆されたぶんようさんの言葉も出てきました。
要約すると以下となります。

:::note info
**作者個人は疑われたほうが嬉しい。
他人との関係においては、「信じるにもかかわらず自分で確認する（疑う）」
という矛盾が生じる。**
:::

>「信じる」というのを「正しいと思う」だと考えると、
>「疑う」は「正しいと思わない」であって、信じるのと疑うのは反対である。
>その考えでいくと、疑われるより信じてもらった方が嬉しいということになりそうである。

>誰かが僕の言ったことを自分で確認もせずにただ信じているとする。
>この場合、信じる人と僕との関係は「信じる」とか「信じない」という言葉だけの関係である。

>一方、別の誰かは僕の言ったことを疑い、自分で確認した上で「やっぱりおまえは正しかった」とか「間違ってるじゃないか」とか言うとする。
>この疑う人と僕の間には同じ現実に接したことによる結び付きが生まれる。
>だとすると、僕としては信じられるより疑われた方が嬉しい。

>意識と行動の両面で他人との結び付きを持つには、
>「信じた上で確認する」ということになる。
>自分で確認するのだから疑うのと同じことである。
>つまり「信じるけれども自分でも確認する」というわけだ。

>自分の中で一貫性を保とうとすると、
>「信じているから確認はしない」か「疑っているから確認する」になってしまう。
>そうすると、他人との結び付きが意識か行動のどちらかに偏るのだ。

>他人との関係においては、
>自分の中に「信じるにもかかわらず自分で確認する」という矛盾を抱える必要がある。

引用
https://www.asahi-net.or.jp/~ng1f-ist/believe.html

# 3.私なりの結論
最後に、私なりの結論を記載して締めにしようと思います。
個人的には七海千秋さんの意見とかなり近いです。

:::note info
**「信じる」と「疑う」は逆のことではない。
信じるためには疑うというステップが必要である。**

**一番最初の業務の例では
「人事考課の自己申告や、案件状況に問題がないこと信じたいから疑う」
のであり、「嘘だと思うから疑う」というわけではない。**

**「全く疑わずに信じる」ことは「信じる」ではなく、「思考停止」に近い。**
:::
:::note warn
もちろん、あくまで私個人の意見で、数年後は変わっている可能性もあります。
:::
:::note warn
上記では「疑う」と記載しましたが、
どちらかというと「確認する」というイメージが近い気がします。
:::

# 4.おわりに
ここまで読んで下さり、ありがとうございます！！！
(^^)

この記事を読んでいただいたみなさんが、
改めて「信じる」と「疑う」について考えるきっかけになれば幸いです。

今回は少しマネジメントに関わる内容だった気がします
また次回も何かしら記事にします♪
(:3_ヽ)_
【個人開発】テキストにコメントを追加するアプリ【Rails】

# はじめに
大学の研究室で、教授に論文を提出し、訂正していただくことがある。
そのようなとき、紙媒体で提出し、そこにコメントをいただいていた。
印刷するのは無駄だし、テキストにコメントをつけるアプリを作ろうと思い開発した。

# 概要
内容はシンプルで、ユーザーが行う操作は次の通りである。
1. 文章追加ページ(/texts/new) から添削したい文書を追加する。
1. 添削ページ(/texts/:id/edit) にアクセスする。
1. コメントを追加したい場所を選択し、右クリックする。
1. 表示されたコメント入力欄にコメントを追加し、追加ボタンを押す。
1. プレビューページ(/texts/:id) にアクセスし、プレビューする。
1. PDF作成ボタンをクリックし、PDF形式でダウンロードする。

コードは次のGitのレポジトリに記載している。
[Gitのレポジトリ](https://github.com/takiAtdu/comment-app)


# 実際の画面
## 文章追加ページ(/texts/new)
文章を入力するページは次のようなフォームにした。
テキストを直接入力するか、PDFファイルで入力できる。![スクリーンショット 2024-03-04 23.56.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626170/97d3d411-a320-ee80-5f7d-11b54df193b5.png)

## 添削ページ(/texts/:id/edit)
入力した文章の添削画面は次のようにした。
左側に文章があり、右側にはコメント入力フォームが出てくる。
![スクリーンショット 2024-03-04 23.58.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626170/68450baa-49ff-89ce-1ac7-ac77cfa7f31d.png)
コメントを追加したい部分を選択し、右クリックするとフォームが表示される。
フォームには、はじめ選択箇所の文章が入力される。
![スクリーンショット 2024-03-05 0.01.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626170/d635a040-45d1-0077-1e20-5022821490f7.png)
[コメントを追加]ボタンをクリックすると、コメントが追加される。
選択したテキストはハイライトされ、コメントと線で結ばれる。
ラインで結ばれる部分はJavascriptで実装した。
![スクリーンショット 2024-03-06 1.08.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626170/e7f8d029-c9f5-78a1-6ce5-ecba277ef003.png)

## プレビューページ(/texts/:id)
![スクリーンショット 2024-03-06 1.08.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626170/384b3c61-77bd-3fea-0e89-f96d3deb3041.png)
プレビューページには[PDFを出力]というボタンがあり、ここをクリックするとPDFが表示される。
PDF出力では、Javascriptでのライン引きができなかったため、カッコ()付きで番号を振り、コメントと対応させた。
![スクリーンショット 2024-03-06 1.10.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626170/6314c626-3356-8627-dc20-554b5bfa9d40.png)

# おわりに
今回は、テキストにコメントを追加するアプリを作成した。
Javascriptは初めて書いたので、少し苦戦した。
HTMLをPDFに変換するのは思った以上に難しく、Webページそのままに表示することは実現できなかった。
サービス提供可能性の表示と予約リンクの動的生成（case when構文によるビューの動的生成）

Ruby on Rails: サービス提供可能性の表示と予約リンクの動的生成

## はじめに

この記事では、Ruby on Railsを使用して、特定の日に特定のサービスが提供可能かどうかを判断し、結果をユーザーに視覚的に表示する方法について解説します。さらに、サービスが提供可能な場合は、ユーザーが直接予約できるように予約ページへのリンクを動的に生成する方法も取り上げます。

## シナリオ

ある会社が複数のサービスを提供しており、それぞれのサービスには複数のスタッフが割り当てられています。スタッフは日ごとに異なるスケジュールで働き、サービス提供の可否はスタッフのスケジュールと提供可能なサービスに基づいています。

## 実装手順

### 1. コントローラーの設定

まず、指定された日に働くスタッフと、15分区切りの時間枠を生成するためのコントローラーアクションを設定します。

```ruby
def for_customer_index
  @date = params[:date].present? ? Date.parse(params[:date]) : Date.today
  @company = Company.find(params[:company_id] || viewing_company.id)
  @working_staffs_on_date = @company.staffs.joins(:schedules).where(schedules: {at_work: true, date: @date}).includes(:services)
  @time_slots = generate_time_slots(@company)
  @service_availability = calculate_service_availability(@company, @date, @time_slots, @working_staffs_on_date)
end
```

### 2. ビューの設定

ビューファイルには、各サービスと時間帯ごとの提供可能性を表示するテーブルを設定し、`○`と`△`の場合には予約リンクを付与します。

```erb
<%# app/views/schedules/for_customer_index.html.erb %>
<table style="border-collapse: collapse;">
  <!-- テーブルヘッダー -->
  <tbody>
    <% @time_slots.each do |slot| %>
      <tr>
        <% @company.services.each do |service| %>
          <td style="text-align: center;">
            <% availability = @service_availability[service.id][slot] %>
            <% if availability == '○' || availability == '△' %>
              <%= link_to availability, new_reservation_path(company_id: @company.id, service_id: service.id, date: @date, time_slot: slot), class: "reservation-link" %>
            <% else %>
              <%= availability %>
            <% end %>
          </td>
        <% end %>
      </tr>
    <% end %>
  </tbody>
</table>
```

## まとめ

この方法を用いることで、ユーザーは直感的にサービスの予約可能な時間帯を確認し、提供可能な時間帯については直接リンクを通じて予約ページに進むことができます。この実装は、予約システムやリソース管理システムなど、さまざまなアプリケーションで応用可能です。
EKSのpodのログを確認する方法

### Podへ接続する
アプリをデプロイする際などにPodがうまく起動しないことがある。
その際、Podのログを見れば解消できる糸口を見つけられることがある
※以下の方法はLinuxのサーバが対象
### 接続方法
ワーカーノードへssh接続する。
var/log/containerの中にPodごとのログファイルは出力されている。
```
cd var/log/container
```
ポッド名ごとにログファイルが出力されているため、「ls」コマンドを打ってファイルを確認することも可能。
以下のコマンドを打って、Podのログを確認する。
```
cat [pod名].log
```
M.2 SSD エンクロージャー RTL9210B-CG firmware update

:flag_jp:Japanese notation

![Windows11_icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/b15ba9ea-c6a0-41f2-2e01-02f98d6d8136.png)

# 覚え書き
::: note
### コントローラー
USB3.1 Gen2 10Gbps
- [Realtek RTL9210](https://www.realtek.com/Product/Index?id=4075)
- [Asmedia ASM-2362](https://www.asmedia.com.tw/product/Ee1YQF9sX7yyajH5/C5cYq34qpByQ6jm6)
- [Jmicron JMS-583](https://www.jmicron.com/products/list/13)


USB4/ Thunderbolt 4: 参考
- [ASMedia ASM2464PD](https://www.asmedia.com.tw/product/802zX91Yw3tsFgm4/C64ZX59yu4sY1GW5/ASM2464PD)
   
[USB 3.x NVMe エンクロージャのチップセットの比較](https://www.station-drivers.com/index.php/en-us/les-dossiers-comment-faire/2989-comparatif-des-chipsets-pour-boitiers-usb-3-x-nvme)
:::

::: note
### RTL9210B-CG
動作確認済みエンクロージャー
<details><summary>Milipow Model SD03</summary>

![51szS4+z1ZL._AC_SL1200_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/d49bb9a7-540f-e1ef-4fe4-b0a44fe55d26.jpeg)

</details>

<details><summary>ElecGear NV2242A</summary>

![51yxNrsSvhL._AC_SL1200_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/49a1714a-fdce-dc94-306b-a3d07501dff9.jpeg)

</details>

**最新ツールダウンロード**

- [bensuperpc/rtl9210](https://github.com/bensuperpc/rtl9210)
- [damnnfo/rtl9210b-firmware](https://github.com/damnnfo/rtl9210b-firmware)

<details><summary>station-drivers.com</summary>

- [Realtek RTL9210 NVMe/USB 3.1 Controller firmware](https://station-drivers.com/index.php/en-us/component/remsearch/?searchword=Realtek%20RTL9210%20NVMe/USB%203.1%20Controller%20firmware&searchphrase=all&Itemid=171)

![スクリーンショット 2024-12-16 215853.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/5e2e669a-50de-db53-f8bd-b6d2d54c6b21.jpeg)

</details>

**ファームウェアアップデート**
- SSDインストール済みエンクロージャをUSBポートに接続
- `UTHSB_MPtool_Lite.exe`を起動
- 各項目をセット（所定フォルダに格納）
  - Device Select：自動
  - Confgure：
  - Firmware Bin：
  - Firmeare GD：
- `Update Device`（左上の赤い上矢印）をクリック
[参考手順](https://station-drivers.com/index.php/en-us/guide-de-mise-a-jour-instruction-information/3303-realtek-rtl9210-nvme-usb-3-1-controller-firmware-version-1-27-24)


アップデート前
![スクリーンショット 2024-12-17 173845.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/119375fb-57db-79bd-7e69-5f05ae023558.jpeg)

アップデート後
![スクリーンショット 2024-12-17 173936.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/8529cabc-2d64-a443-fad9-3f51f9c6aa96.jpeg)

20秒で終わる

:::

# あとがき
NV2242Aで認識しなかったSATA SSDが認識した
SSDが認識しなかったら故障を疑う前にファームウェアを更新してみよう
ツールはどちらからDLしても良いだろう
受け取ったファイル名をos.path.joinで処理する時の注意

ほとんど以下の記事に書いてあることと同じなのですが、やらかしてしまったのでメモします。

https://qiita.com/FGtatsuro/items/1ab9ebf6505bef1834f8

os.path.join は以下の仕様になっています。

> 引数に絶対パスがあると、その前の引数は無視されるので注意。

基本的にこれだけなのですが、この仕様を知らずにどのようなやらかしをしたのか紹介します。

## バグっているコード
ファイル名が入力されて、なんらかの処理をした上でテンポラリディレクトリに書く処理があったとします。

```python
from tempfile import TemporaryDirectory
import os

def func(filename: str):
    with open(filename, "r") as f:
        some_str = f.read()
    
    # なんらかの処理
    
    with TemporaryDirectory() as tmp_dir:
        with open(os.path.join(tmp_dir, filename), "w") as f:
            f.write(some_str)
        # テンポラリファイルを使ったなんらかの処理
```

このとき、`filename`がファイル名なら上手く動きます。

## 絶対パスが入力された場合
`filename`に絶対パスが入力された場合、前述の仕様によって`os.path.join(tmp_dir, filename)`は`filename`を返します。

したがって、この場合、元のファイルを上書き、いや破壊してしまいます。

これを避けるには、`filename`からbasenameを取り出す必要があります。

```python
    with TemporaryDirectory() as tmp_dir:
        with open(os.path.join(tmp_dir, os.path.basename(filename)), "w") as f:
            f.write(some_str)
        # テンポラリファイルを使ったなんらかの処理
```

## 相対パスが入力されたとき
実は一番最初の例にはまだバグがあります。
`filename`に`path/to/file`のような相対パスが入力されたとき、テンポラリディレクトリの下にそのようなサブディレクトリはないので`FileNotFoundError`を返します。

これはエラー落ちするだけですが、もう一つ、もっと深刻なバグがあります。
最初の例にはディレクトリトラバーサル脆弱性があります。
`os.path.join`は`..`のような表現も結合するので、
```python
    filename = "../../etc/passwd"
    with TemporaryDirectory() as tmp_dir:
        with open(os.path.join(tmp_dir, filename), "r") as f:
            print(f.read())
```
などとすれば見えてはいけないものが見えてしまいます。

この例では、`filename = "/etc/passwd"`　でもアウトです。

## 余談
os.path.join がディレクトリトラバーサル脆弱性を生みやすいのは割と有名なようです。

https://security.openstack.org/guidelines/dg_using-file-paths.html

https://blog.hamayanhamayan.com/entry/2023/07/31/213302

上のOpenStackのガイドラインでは、ファイルを読む前に、ベースパスの配下にあることを確認しています。
```python
import os
import sys

def is_safe_path(basedir, path, follow_symlinks=True):
    # resolves symbolic links
    if follow_symlinks:
        matchpath = os.path.realpath(path)
    else:
        matchpath = os.path.abspath(path)
    return basedir == os.path.commonpath((basedir, matchpath))


def main(args):
    for arg in args:
        if is_safe_path(os.getcwd(), arg):
            print("safe: {}".format(arg))
        else:
            print("unsafe: {}".format(arg))

if __name__ == "__main__":
    main(sys.argv[1:])
```


## まとめ
- 外部入力されたファイルパスの結合は意外と大変
- ファイル名だけ入力してテストしているだけでは不十分
- ディレクトリトラバーサルに注意

より良い方法があればぜひ教えてください。
wifiをパケットキャプチャ on Mac

# MacbookでWifiのパケットキャプチャを行う

## まず初めに
[WireShark](https://www.wireshark.org/download.html)を入れよう！
このソフトを使うと，パケットキャプチャが楽しくなってしまう・・・

## 自分の接続しているWiFi情報を確認する

Alt + Wifiのマークをクリックすると確認ができる．
![スクリーンショット 2024-03-06 0.15.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256914/5da00662-35c2-712b-2ac5-0dd8aeacc03a.png)

そうすると，こんな感じの画面が開ける．
これの，チャンネルという部分に注目して欲しい．
11(2.4Ghz, 20Mhz)

## スニファする！！
![b77b36551635c2a446f348feaec2ab52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256914/333621e5-8e63-4519-ef83-c577a7ae04d5.png)
こんなマークのアイコンはないだろうか？ワイヤレス診断というアプリを開く．
![4bb4567f0f6fc37a4de393f117e2f192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256914/ab24e775-9f65-7937-503d-73ad5ac4b343.png)
こんな感じの画面が開く．
このアプリを一番上にした状態で，画面左上のウィンドウを押す
![スクリーンショット 2024-03-06 0.18.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256914/947bf5aa-bf19-76be-2e88-0eb23c6e900e.png)
![スクリーンショット 2024-03-06 0.19.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256914/66063837-2518-a277-3db9-ad3c6e631ccb.png)
![1ac4e1c59f4908068070f83327991442.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256914/baae513e-1bf9-2c4b-23ea-4b4c1a8129a0.png)
ここで，先ほど見たチャンネルと幅が役にたつ．
開始をクリックする．
始まると一時的に自分はネット接続ができなくなる，，，はず．
止める時は中止を押す．
![スクリーンショット 2024-03-06 0.23.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256914/1c6d2269-ddbd-a57b-ebc3-93a2f8a56fa4.png)
自分の場合はここから/var/tmpを指定しているが，何かいい方法がある人はコメントをして欲しい．．
/var/tmpに.pcapファイルが作成される．それをWireSharkで開くと，WiFiのパケットキャプチャができる！

※tmpフォルダにあるものは再起動時などに消えてしまうので，保存したい場合は移動することをお勧めします．
VBAでワークブックを開くスクリプト

初めての投稿になります。

# ワークブックを開くスクリプト
私は日常業務でエクセルファイルを自動で開いて処理していますが、エクセルファイルを安定して開くためのスクリプトをFunctionプロシージャにまとめて活用しています。
以下のような観点で設計しています。

* 開いたエクセルファイルをWorkbookオブジェクト変数に格納する。
* 新しく開くファイルは読み取り専用で開く。
* ファイルの閉じ忘れがあっても処理を続行したい。
ファイルが既に開かれた状態で同じファイルを開こうとするとエラーになるので、ファイルが既に開かれているならそれをそのまま利用したい。
* このプロシージャで処理できない場合は**Nothing**を返す。

```vb
Function wbOpen(ByVal fullpath_WB As String) As Workbook
		Dim L As Long, filename_WB As String
		L = InStrRev(fullpath_WB, "\", , vbBinaryCompare)
		filename_WB = Mid(fullpath_WB, L + 1)
On Error GoTo ERR1
		Set wbOpen = Workbooks(filename_WB)
		Exit Function
ERR1:
On Error GoTo ERR2
		Set wbOpen = Workbooks.Open(Filename:=fullpath_WB, UpdateLinks:=0, _
														   ReadOnly:=True)
		Exit Function
ERR2:
		Set wbOpen = Nothing
End Function
```

上記のコードを利用すれば、ファイルのフルパスさえ正しければファイルはほぼ確実に開けます。
`Workbooks.Open`メソッドでは`UpdateLinks:=0`、つまりリンクを更新しない設定にしています。これは以下の理由によります。
* 業務のエクセルファイルではリンク（外部参照）で更新される**意味のあるデータ**はない。
* その代わりに無意味なリンク（**リンク先が存在しないファイルになっていてエラーを吐いているリンクなど**）が大量にある。これは長年の安易なコピペ操作の繰り返しで蓄積されたもの。他人が作業したファイルには高確率でこれが含まれるので、この無意味なリンクを避けることは難しい。
* `UpdateLinks:=3`などとしてリンクを更新設定にした場合、無意味なリンクを延々と更新しようとする。時間を食うだけで何にもならないので、最初からリンクは更新しないことにしている。

私はこのプロシージャを別のプロシージャの繰り返し文（For文など）の中に組み込むなどして、効率的にエクセルファイルを操作しています。
端末環境によってはフォルダ区切り文字が「¥」ではなく「/」だったり「\」だったりしますが、上記コードを流用される場合は端末環境に合わせて適宜調整してください。
【Ruby】問題集解答 Part3（paizaラーニング）

# N個のデータの入力 (paizaランク D 相当)
https://paiza.jp/works/mondai/stdin/stdin_n
### 自分の解答
せっかく受け取った`num`を上手く使っていないのが美しくない気もするが、前回ChatGPTから教わったことを活かしたいと考え、`split`を使った。
```ruby:practice_01.rb
num = gets.to_i

array = gets.chomp.split

puts array
```
「2行目でN個の文字列が半角スペース区切りで与えられます。」とあるが、上記のコードにおいては、最初に受け取ったN個分の入力しか許さない仕様にはなっていないところが減点ポイントかもしれない。

### ChatGPTの解答
以下は、与えられた条件に基づいて標準入力からN個の文字列を受け取り、順にN行で出力するRubyのコードです。

```ruby
# Nの値を受け取る
n = gets.to_i

# N個の文字列を半角スペース区切りで受け取り、配列に格納する
strings = gets.split

# 配列の要素を順に出力する
strings.each do |str|
  puts str
end
```

このコードを実行すると、標準入力からNとN個の文字列を受け取り、その文字列を順にN行で出力します。

### 学び
ChatGPTの解答も自分の解答と同じで最初に受け取った数値をまったく活かしていない気がするけど...？
ChatGPTの使い方の勉強も必要だと感じた。
「checking macOS SDKROOT... xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools)...」の対処法

久々に個人で開発してみようと思い、過去に構築(荒廃)したpython環境をリセットした後、
pythonをインストールしようと思ったら以下のエラーが発生。

```
checking macOS SDKROOT... xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
```



エラーを見た感じXcodeのコマンドラインツールが見つからないっぽい。
とりあえずググってみると以下の記事が。
どうやらMacOSをアップデートすると起きるらしい。
https://forums.developer.apple.com/forums/thread/673827

以下のコマンドを実行してXcodeのコマンドラインツールをインストールしたら直りました
```
xcode-select --install
```
継承

継承は親クラスの持つメソッドやフィールド等を子クラスに引き継がせることができます。
継承を用いると子クラスが親クラスの機能を全て利用できる為、機能の本質が似通っている類似クラスを容易に作成できます。

ただしクラスの多重継承は禁止されています。
また、安易な継承はクラスの参照元を増やす事や不要な機能の追加にも繋がり、コードが読みにくくなります。
その為、委譲等の類似機能での代用が可能か常に考える必要があります。
Linuxユーザーとグループ管理コマンド - ユーザーの削除


# ユーザーの削除

`userdel` コマンドは Linux のユーザーを削除するために使用されます。

## フォーマット：

```
userdel [options] LOGIN
```

## よく使うオプション

- `-f` | `--force` # 強制削除。ログイン状態のユーザーでも削除する
- `-r` | `--remove` # ホームディレクトリとメールスプールを削除する

## 例：

### ユーザーの作成とパスワードの設定

```shell
[root@rocky8 ~]# useradd zhangsan
[root@rocky8 ~]# passwd zhangsan
Changing password for user zhangsan.
New password:
```

### 関連データの確認

```shell
[root@rocky8 ~]# id zhangsan
uid=1004(zhangsan) gid=1004(zhangsan) groups=1004(zhangsan)

[root@rocky8 ~]# ll -a /home/zhangsan
total 12
drwx------. 3 zhangsan zhangsan 78 Jun 25 15:32 .
drwxr-xr-x. 7 root root 74 Jun 25 15:32 ..
-rw-r--r--. 1 zhangsan zhangsan 18 Jul 27 2021 .bash_logout
-rw-r--r--. 1 zhangsan zhangsan 141 Jul 27 2021 .bash_profile
-rw-r--r--. 1 zhangsan zhangsan 376 Jul 27 2021 .bashrc
...

[root@rocky8 ~]# ll /var/spool/mail/zhangsan
-rw-rw----. 1 zhangsan mail 0 Jun 25 15:32 /var/spool/mail/zhangsan
```

### 別のターミナルで zhangsan としてログイン

```shell
[zhangsan@rocky8 ~]$ whoami
zhangsan
```

### ログイン中のユーザーの削除に失敗

```shell
[root@rocky8 ~]# userdel zhangsan
userdel: user zhangsan is currently used by process 5162
```

### 強制削除

```shell
[root@rocky8 ~]# userdel -f zhangsan
userdel: user zhangsan is currently used by process 5162

[root@rocky8 ~]# id zhangsan
id: ‘zhangsan’: no such user
```

### 削除後のエラー

```shell
[zhangsan@rocky8 ~]$ whoami
whoami: cannot find name for user ID 1004
```

### ユーザーが削除された後、そのユーザーのファイルの所有者が表示されなくなり、UID のみが表示される

```shell
[root@rocky8 ~]# ll -a /home/zhangsan
total 16
drwx------. 4 1004 1004 131 Jun 25 15:45 .
drwxr-xr-x. 7 root root 74 Jun 25 15:32 ..
-rw-------. 1 1004 1004 58 Jun 25 15:45 .bash_history
-rw-r--r--. 1 1004 1004 18 Jul 27 2021 .bash_logout
-rw-r--r--. 1 1004 1004 141 Jul 27 2021 .bash_profile
-rw-r--r--. 1 1004 1004 376 Jul 27 2021 .bashrc
drwx------. 3 1004 1004 19 Jun 25 15:39 .config
...

[root@rocky8 ~]# ll /var/spool/mail/zhangsan
-rw-rw----. 1 1004 mail 0 Jun 25 15:32 /var/spool/mail/zhangsan
```

### 元のユーザーの UID を使用して新しいユーザーを作成すると、元のユーザーのファイルを継承できる

```shell
[root@rocky8 ~]# useradd -u 1004 lisi

[root@rocky8 ~]# ll /home/
total 4
drwx------. 3 lisi lisi 78 Jun 25 15:48 lisi
drwx------. 4 lisi lisi 131 Jun 25 15:45 zhangsan
...

[root@rocky8 ~]# ll /var/spool/mail/
total 0
-rw-rw----. 1 lisi mail 0 Jun 25 15:48 lisi
-rw-rw----. 1 lisi mail 0 Jun 25 15:32 zhangsan
...
```

### ユーザーファイルの削除

```shell
[root@rocky8 ~]# userdel -r lisi

[root@rocky8 ~]# ll /home/lisi
ls: cannot access '/home/lisi': No such file or directory

[root@rocky8 ~]# ll /var/spool/mail/lisi
ls: cannot access '/var/spool/mail/lisi': No such file or directory
```
omniauth_openid_connectのリダイレクト先でrequest.env['omniauth.auth']がnilの解決法

## あれ

railsでomniauthとomniauth_openid_connectでCognitoの認証するぞ〜ってなってリダイレクト後の処理がはまったあれ

## 結論

なぜかrequest.env['omniauth.auth']がnilになってしまたあなたへ
たぶんコールバックのURLが auth/:provider/callback ではない場合にこうなる模様

解決法として `callback_path` を追加する

```ruby:config/initializers/omniauth.rb

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :openid_connect, {
    issuer: "https://cognito-idp.リージョン.amazonaws.com/プールID",
    discovery: true,
    scope: [:openid],
    response_type: :code,
+   callback_path: "/my/custom/callback", # ここにcallback_pathを追加！！
    client_options: {
      identifier: "***",
      secret: "***",
      redirect_uri: "http://exapmle.com/my/custom/callback",
    }
  }
end

```

```ruby:controllers/session_controller.rb
class SessionsController < ActionController::Base
  def create

    # きっとするとnilじゃなくなる
    auth_hash = request.env['omniauth.auth']
  end
end
```


```ruby:config/routes.rb
# やんごとなき理由で auth/:provider/callbackじゃないケース
get 'my/:provider/callback' => 'sessions#create'
```

## たぶん

auth/:provider/callback の形式のURLをコールバックにしとくのが無難
VSCodeで常に新しいウインドで開くための設定

# なぜこの設定をしたかったのか?
* 横断検索を利用する際に、複数ファイルが存在すると検索結果のノイズになるのが煩わしかった
* Windowsの仮想デスクトップ利用時に別のデスクトップでVSCodeが開かれている状態で新しいファイルを開くと、デスクトップが勝手に切り替わってしまうのが煩わしかった

# 設定方法
1. 設定を開く

    ![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505647/3e49aada-5a2c-bd6f-627f-20414cb05fc1.png)

2. ユーザー > ウィンドウ > 新しいウィンドウ の以下の設定を`on`にする
    * Open Files In New Window
    * Open Folders In New Window

    ![手順2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505647/0a67461d-3d69-304c-85ae-4780f450899e.jpeg)

この設定をすることで、ファイルをダブルクリックしたときや、フォルダ右クリック > Codeで開く を行ったときに、新しいウインドで開かれるようになりました。
もし同じ悩みを持つ方がいれば一度設定してみることをおすすめします。

最後まで読んでくださりありがとうございました。

# 参考
https://std9.jp/articles/01fmxxyd4tzpj5te1bvcnrg1r1
Digital Marketing

I have established myself at the forefront of fast-paced digital marketing, a career I have thrived upon due to my familiarity and success in the industry. Over a career spanning more than a decade, I constantly proved to have the best market acumen in the ever-changing and evolving marketplace of digitization and internet revolution which would make me an ideal go-to person for companies willing to innovate their marketing strategies.
And it is through digital marketing that I found my path to use technology in an effective manner that would connect businesses to customers. With a formality of business degree, along with marketing and an innate ability to predict changes, soon I maneuvered my way through the maze of online portals and the algorithm puzzle.
During my career, I worked out skills in different directions of digital marketing SEO optimization, creating content, promoting products through social media, and data analysis. Such an integrated approach suggests that the general strategy for going online must be planned in such a way so that nothing hinders reaching multiple channels as well as platforms but at the same time, it is systemized enough to bring up the necessary outcome.
My success is not built only on technical prowess but the ability to adapt to the ever-dynamic change in the landscape of digital marketing. I identify emerging trends and I know exactly how to execute them just so I can get ahead of the competition for my clients. Be it using the potential of social media influencers or enhancing voice search, I always know how to stay at the front.
I have worked with clients, which include e-commerce giants to small startups that have all benefited from my strategic advice and methods based on explained data.
The fundamental aspect for which my clients refer to me as a trusted advisor is because of my developed ability to assist create digital marketing conceptualization that can be put into practice, measured, and offer real upshots.
My bio is a testament to my commitment to knowing the trends, being on top of them, and above all innovating towards making the digital marketing industry a better place suited for business today and tomorrow. As the scope and nature of digital continue to change, I remain committed to the success of business in today’s business world. 
https://www.scoop.it/topic/stuart-von-moger/p/4151378586/2024/03/04/digital-marketing