OmniAICreator/Qiita-1.07M huggingface dataset:
Arduino IDE + Raspberry Pi Pico + ESP-01で時計

## 概要
Raspberry Pi Pico と ESP-01 で時計を作成します。
時刻はSNTPで取得します。
下記のWiFiライブラリーを利用します。
https://github.com/JAndrassy/WiFiEspAT

![IMG_20250129_190410508_S.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670759/a4699a6d-d056-f174-025d-9c7c7970e309.jpeg)
写真の赤線の枠内が ESP-01 です。

## 開発環境
Arduino IDE for Raspberry Pi Pico on Windows 11
## 材料
+ [Cytron] Maker Pi Pico Base　(開発用基板)
+ Raspberry Pi Pico
+ ESP-01(WiFi module)
+ SSD1306(OLED)
+ GROVE - 4ピン-ジャンパメスケーブル
## 詳細
サンプルプログラム SNTPTime が動くように修正します。
AT+CIPSNTPTIME? コマンドの返値の文字列を time_t 型に変換します。

Arduino\libraries\WiFiEspAT\src\utility\EspAtDrv.cpp を下記のように修正します。

sntpTime関数の上にparseTimeString関数を追加します。
```c:parseTimeString()
unsigned long parseTimeString(const char* timeString) {
  static const char *md[] = {"Jan", "Feb", "Mar", "Apr",
  	"May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  char dayName[4], monthName[4];
  int month, year;
  struct tm tm;

  sscanf(timeString, "%s %s %d %d:%d:%d %d",
  	dayName, monthName, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &year);
  for(month=0; month<12; month++) if (strcmp(md[month], monthName) == 0) break;
  tm.tm_year = year - 1900;
  tm.tm_mon = month;
  return mktime(&tm);
}
```
sntpTime関数を下記の通り修正します。
```diff_c:sntpTime()
unsigned long EspAtDrvClass::sntpTime() {
  maintain();

  LOG_INFO_PRINT_PREFIX();
  LOG_INFO_PRINTLN(F("SNTP time"));

#ifdef WIFIESPAT1
-  cmd->print(F("AT+SNTPTIME?")); // AT LoBo firmware command
+  cmd->print(F("AT+CIPSNTPTIME?"));
-   if (!sendCommand(PSTR("+SNTPTIME")))
+   if (!sendCommand(PSTR("+CIPSNTPTIME")))
    return 0;
-  char* tok = strtok(buffer + strlen("+SNTPTIME:"), ",");
+  char* tok = buffer + strlen("+CIPSNTPTIME:");
-  unsigned long res = strtoul(tok, NULL, 10);
+  unsigned long res = parseTimeString(tok);
#else
  cmd->print(F("AT+SYSTIMESTAMP?"));
  if (!sendCommand(PSTR("+SYSTIMESTAMP")))
    return 0;
  unsigned long res = strtoul(buffer + strlen("+SYSTIMESTAMP:"), NULL, 10);
#endif
  readOK();
  return res;
}
```
## まとめ
WiFiEspATライブラリーは ESP8266_AT_LoBo Firmware に対応しています。
AT+SNTPTIME?
+SNTPTIME:1556721502,2019-05-01 14:38:22
https://github.com/loboris/ESP8266_AT_LoBo

私が入手したESP-01は下記のコマンドになっています。
AT+CIPSNTPTIME?
+CIPSNTPTIME:Sun Feb 02 10:07:55 2025
Firmwareの更新は難しそうなので WiFiEspAT ライブラリーの修正で対応しました。

この投稿にはOLEDへの表示処理は含めていません。
【電脳少女プログラミング2088 ─壊レタ君を再構築─】「打ち捨てられた図書館」で正解判定されるSQLが微妙な件について

# はじめに
本記事では先日リリースされたプログラミングゲーム「電脳少女プログラミング2088 ─壊レタ君を再構築─」のSQLスキルチェックステージ「打ち捨てられた図書館」について触れていきます。
ゲームの詳細は下記をご覧ください。

https://paiza.jp/entry/denno2088_qiita

# 前提
筆者が普段使用するRDBMSはほとんどがOracle Databaseです。もう10年以上お付き合いしているデータベースなので、どっぷりとOracle色に染まっています。
MySQLも今やOracleの持ち物ですが、最後に触ったのは7〜8年前で、今回久々に触ることになりました。

# ステージのポイント

３つのテーブルをJOINする点と、下記抽出条件を実装する点が、「打ち捨てられた図書館」のポイントになります。

> log (ログ) の log.created_at (ログ.作成日) が 2085-08-01 〜 2087-10-20 の期間の memory.id (記憶.ID), memory.talk (記憶.会話内容), battle.result (戦闘.結果) を出力してください。

※問題文より一部抜粋

ER図では、ログ.作成日はdate型であることが示されています。
その他、前提となる条件に関しては特段触れられていません。

# 私の解答
私が解答したSQLは以下の通りです。

```sql
SELECT
    memory.id,
    memory.talk,
    battle.result
FROM
    log
JOIN
    memory
        ON log.memory_id = memory.id
JOIN
    battle
        ON log.battle_id = battle.id
WHERE log.created_at BETWEEN STR_TO_DATE('2085-08-01', '%Y-%m-%d')
    AND STR_TO_DATE('2087-10-20 23:59:59', '%Y-%m-%d %H:%i:%s');
```

この解答に対するレイミさんのご意見（性格：ドS系）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551450/6f74d344-7f29-3e59-1e57-cca1fcd51e72.png)

褒めてもらえました。
~~重箱の隅をつつくような、細部まで目を光らせて、もはや言いがかりでは？と思えるほどの指摘を挙げてきて、メタクソに罵られることを期待して性格をドS系にしたのに、~~ レイミさんが優しすぎる。

# その他の正解

他の方はどのような解答をしているのか見てみたら、どうやら以下のSQLでも正解となる様子。

```sql
SELECT
    memory.id,
	-- 中略 --
FROM
	log
    -- 中略 --
WHERE
	log.created_at BETWEEN '2085-08-01' AND '2087-10-20';
```

`WHERE`句の条件が、私の書き方と異なっています。
「えっ！？これ正解扱いでいいの！？」と思い、実際に試してみたら本当に正解になりました。
この時のレイミさん（ドS）の反応。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551450/8736dfa4-933e-41c9-601a-ef1ce575009e.png)
手堅くないSQLってどんな構成なんだろう？

# 個人的に引っかかったポイント
「電脳少女プログラミング2088 ─壊レタ君を再構築─」ではMySQLの文法でSQLを書く必要があります。
なので、私が最初に解答したSQLでは`STR_TO_DATE`関数を噛ませて、データ型に対する暗黙変換が行われないようにしています。この関数はOracle Databaseでは使えませんが、そちらでは`TO_DATE`関数が類似する関数として用意されています。

その点を踏まえつつ、MySQLではDATE型でどのような値を扱うかが大きなポイントになります。

## MySQLでカラムに設定できる、日付に関する型の種類

* DATE
* TIME
* DATETIME
* TIMESTAMP
* YEAR

https://dev.mysql.com/doc/refman/8.0/ja/date-and-time-types.html

さらに、DATE型に関しては次のように値を持つことが定められています。
> DATE 型は、日付部分を含むが時間部分は含まない値に使用されます。

https://dev.mysql.com/doc/refman/8.0/ja/datetime.html

# 私の解答、冗長ですよね
以上を踏まえると、私の解答したSQLの一部が、冗長であることがわかります。
具体的には`STR_TO_DATE('2087-10-20 23:59:59', '%Y-%m-%d %H:%i:%s')`の部分。
比較対象がDATE型のカラムなのだから、あえて23時59分59秒を指定する必要性は全くありません。私がいつも使っているOracle DatabaseではDATE型に時分秒を持つので、当たり前のように書いてしまった箇所が、実はMySQLだと不要であることがわかりました。

# 指摘して欲しかった
私の解答も文法的には間違っていなかったものの、MySQLのクエリとして最適ではありませんでした。確かに構文上はエラーにならないし、自動テストで拾えないタイプの不具合です。
ですけど、こういった「正しい結果を得られるが、エレガントではない」SQLこそレイミさんからフィードバックしてもらえると、より勉強になるだろうと思いました。

:::note warn
特に、今回はたまたまQiita内イベントで他の記事に目を通す機会があったから気付けただけに、もしイベントに参加していなかったら、私はこの誤りに気づくきっかけさえ得られなかった可能性が高いです。
:::

もう一点、2例目のクエリでは暗黙の型変換を行っています。こちらも大抵の場合きちんと動いてくれるのですが、私のようなおじさん世代は「DBに暗黙の型変換をやらせるな」みたいなSQL開発標準が定められているプロジェクトを多々見てきたので、この点も何らかの示唆をレイミさんからフィードバックしてもらえたら良いな、と思いました。
よくありがちな日付書式`RR-MM-DD`が悪さを働くことがありますので。

# まとめ

日付型の扱いはRDBMSも勿論の事、プログラミング言語ごとにかなり個性が出る傾向を感じます。
初めて、あるいは久しぶりに触れる、プログラミング言語であったりデータベースでは、必ず日付型の扱いに目を通しておくようにしましょう。
読書ログ - ソフトウェア開発現場の「失敗」集めてみた。


## 本のタイトル
ソフトウェア開発現場の「失敗」集めてみた。
[amazon link](https://www.amazon.co.jp/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E7%8F%BE%E5%A0%B4%E3%81%AE%E3%80%8C%E5%A4%B1%E6%95%97%E3%80%8D%E9%9B%86%E3%82%81%E3%81%A6%E3%81%BF%E3%81%9F%E3%80%82-42%E3%81%AE%E5%A4%B1%E6%95%97%E4%BA%8B%E4%BE%8B%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%81%E3%83%BC%E3%83%A0%E9%96%8B%E7%99%BA%E3%81%AE%E3%81%86%E3%81%BE%E3%81%84%E9%80%B2%E3%82%81%E3%81%8B%E3%81%9F-%E5%87%BA%E7%9F%B3-%E8%81%A1%E5%8F%B2/dp/4798185183)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3973326/26f7fecd-797b-fe7c-2257-950a9700cacf.png)


## 著者
出石聡史

## 読んだ日
- 2024/12/27-30

## 感想
### 印象に残った・学んだ部分 😊
- バグはすべて直すべきでない。 以下の優先順位で考える
    1. 演算ミス
    1. データを壊してしまうバグ
    1. クラッシュバグ
    1. 仕様ミス（仕様と違う実装）
    1. GUI上のバグ
    1. 翻訳ミス
    1. 再現頻度が極端に低く、致命的ではないバグ
    1. ありえない操作で発生するバグ
    1. 仕様と違うけど、別に誰も気にしないバグ

- 仕様は明確に伝わっていないことを理解する
- 業界用語が齟齬を生む

### 自分のアクション 🤔
#### Must
- バグ修正対象の優先順位を作成し、周知する
- ユーザーはソフトを信じているという前提で演算ミスの重要性を唱える
- 業界用語による齟齬防止のために用語集の箱を作成。みんなで育てられるものにする。

#### Nice to have
- 仕様は明確に伝わらないという前提からユーザー利用シーンを書く

## 総合評価 ⭐
（5点満点で評価）
★★★☆☆
備忘録

# 目的
 本記事はweb記事を書くうえで大切だと思ったことの備忘録です．IT向けというよりは，現状の記事があまりにも杜撰になってきたのであららめて，何をどうまとめてどうしてフォーカスするのか，また生成AIが発達する上で必要になりそうな技術について，大学生なりの視点でまとめた物です．当たり前だろという意見が出てくるような初歩的な事について述べています．くだらないと思ったらブラウザバック推奨です．
 また，本記事は私の意見であり，特に特定の第三者を貶めるようなつもりはありません．炎上は勘弁です．文章中問題となる内容がりましたらご指摘をお願いしたいです．
 
# 内容
まず，今週[この本](https://www.amazon.co.jp/%E3%80%8C%E5%85%B7%E4%BD%93%E2%87%84%E6%8A%BD%E8%B1%A1%E3%80%8D%E3%83%88%E3%83%AC%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0-%E6%80%9D%E8%80%83%E5%8A%9B%E3%81%8C%E9%A3%9B%E8%BA%8D%E7%9A%84%E3%81%AB%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B29%E5%95%8F-PHP%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E6%96%B0%E6%9B%B8-%E7%B4%B0%E8%B0%B7-%E5%8A%9F/dp/4569845991)を読みました（まだ全部読み終えていません．）．細川功著「具体⇔抽象」トレーニングです．私が気づかされ，また必要な考えだと思った項目は以下の通りです．

- 抽象と具体の関係
- 抽象化するための問い
- 構造的な情報

下記が抽象と具体の端的なライフサイクルです．
```mermaid
graph TD;
    A[具体的な内容] -->|抽象化| B[抽象的な概念];
    B -->|具体化|A

```


## 抽象と具体の関係

具体：物事を直接視認または確認できる状態であること
抽象：物事の側面，属性，その他の要素を確認できること

上記が私の中での具体と抽象を辞書で引いて解釈したものです．つまり言いたいのは具体的な状態から知りたい情報にフォーカスしたのが抽象化ということで情報の構造以下のピラミッドで表すことが出来ます．
![[Pasted image 20250202123333.png]]
抽象的な情報であるほど無駄な情報が少ない，つまり情報が圧縮されていることを上記の図は表しています．
これをプログラミングで例えると，プログラムの内容や挙動を詳細に説明することが具体的な情報で，プログラムがどんな働きをするかを示したものが抽象的な情報です．
ここで，人に説明するときではどんな情報を伝えるとなったとき何をどこまで説明するか分からない，そのようなケースが日常生活のほとんどであると考えます．したがって次にその今の私の答えを示します．

## 抽象化するための問い

  結論から，**今焦点を当てているモノはどこ？**（私の言語能力ではこれが限界でした．）
それが知りたいんだよと思った方，私もそれが知りたいです．しかし方程式は時と場合によって千差万別です．一つの解などは存在しないです．
例えば，身近な話でいうところのSNSで議論されている?内容，批判を恐れず発言するのであれば，政治的な話や宗教，男女間のおごるおごらない，夫婦間の家事問題．
私自身の思想が偏っていますが，話している立場や定義する問題の内容や影響の偏りが個々で異なることを考慮せず，一般化していることが問題であると考えました．つまり，自分の置かれている状況を一般的な内容か？自身の内容か？というようなことを記載せず断片的な情報ばかりをSNSという媒体で投稿することでこのような不毛な争いに発展していることに気づきました．

 また最近の私の出来事，インターン先でのプレゼンに置き換え，考えてみました．
 (background: インターン先である物について調査を行い，まとめて発表した．
			 以下の内容は，守秘義務の観点から多少ぼやかしています．）
			 
 今振り返ってみると，以下の内容が不足していることが分かりました．
- 誰（もしくはどの立場の人）が聞きに来るか？
- 相手方は現状どのような立場か？
- 抽象的な目的と具体的な目的は何？

特に，私が聞くべきだったのは3項目目の「抽象的な目的と具体的な目的」でした．まず，抽象的な目的でおおよその全体像を把握しつつ，次の具体きな目的からその人がどこに着目しているのかを深く分析するべきだったと後悔しました．つまり，抽象的な内容と具体的な内容のギャップから問いを逆算しようと考えました．

```
具体的な情報 ＋ 問い ＝ 抽象的な言い換え
```

上記の式が成立していると仮定しています．この式を端的に言い換えるとコミュニケーション能力という抽象化が出来ます．だからコミュ力って大切なんですね，納得しました．

## 構造的な情報

構造的な情報．
この単語を見た時，私の中のもやもやを言語化してくれた言葉です．昨今生成AIが急速に発達し，誰もが多くの情報をアクセスできるようになり，分からない内容で，知らない検索できない情報でもとりあえず尋ねると教えてくれるようになりました．しかし，情報によりアクセスできるようになっただけで私自身の脳内で整理されず，情報同士の上下関係，類似関係を不明慮にしていることに気づかされました．
一般的に聞いたら確かに答えてくれる生成aiですが，LLMは統計的にそう答えてくれるというだけで知らないことを知っていると知っている状態にしてくれるけれど，周辺知識については知っている前提で出力してくることが問題だと私は解釈しました．
例えば，私はdcokerについて勉強しているのですが，聞いた範囲については答えてくれるのですが，聞いていない情報，当たり前の周辺知識への無頓着であり，例えば初学者は何を知ればいいかもわからないから聞きようがないという盲点でずっとつまずいていることに気づきました．それと同時に体系化された情報，つまり整理され学べる形の情報に付加価値が付いているということに改めて気づきました．大学やUdemyなどの体系化され学べる環境が支持されている状況がよくわかりました．

ここで私は今回から次のようにweb記事の作製を行ってみようと思います．

1. これはどんな目的か？
2. どんな状況であるか？
3. どこまでの範囲について記述しているか？
4. 内容(私の友が理解できるようにまとめ直されているか？)

散見された情報をまとめ，整理し，それを抽象化して理解度を深めることが社会に出た時に必要な技術だと思います．

# 今後の展望

最近の私のweb記事を振り返ってみるとQittaに投稿することを目的としていて，本来の目的である，文章作成能力，及びコミュニケーション能力の向上とかけ離れており，大きく反省します．
また，最近何をやりたいのか不明慮になりいろいろなものに手を出して中途半端な状況になっているため，ここで今週はdockerの勉強し，AtCoder用のキョウプロ環境とFlutter用のアプロケーション開発環境，dify用の開発環境を作製するとを目標とします．
Mac で Vim の日本語入力（Linux併用）


Mac で Vim を使う際に、日本語入力をスムーズに行うにはどうすればよいか？

Vim の日本語入力には、大きく分けて **2 つの方法** があります。

1. **Mac の IME（Google 日本語入力など）を利用する**
2. **Linux 風に Vim 内部で日本語を処理する（fcitx, ibus など）**

それぞれのメリット・デメリットを比較し、どちらを選ぶべきか。。


## **要約**
✅ **Mac の IME をそのまま使うのが簡単でおすすめ！**  
✅ **Vim を本格的に使うなら `fcitx-remote` で IME の自動切り替えを設定！**  
✅ **Linux でも Vim を使うなら `fcitx`, `ibus` などを活用すると快適！**  

 **結論: Mac の IME を使いつつ ターミナルの中で、`fcitx-remote` を活用？！** 



---

## 1. Mac の IME を使う

### **特徴**
- macOS の IME（標準日本語入力 or Google 日本語入力）をそのまま使用
- `i` や `a` で挿入モードに入ると IME が有効になる
- 特に追加設定が不要

### **メリット**
✅ **設定不要で簡単**
- そのまま使えるので、特別な環境構築が不要

✅ **Google 日本語入力の高精度な変換を使える**
- 予測変換や辞書機能が利用可能

✅ **システム全体で統一感がある**
- Vim 以外のアプリでも同じ IME を使える

### **デメリット**
❌ **Vim との相性が悪いことがある**
- `Esc` を押したときに未確定文字が残ることがある
- IME の切り替え遅延が発生することがある

❌ **キーバインドとの競合**
- `Ctrl + P`（補完）や `Ctrl + N`（候補選択）が IME のショートカットと衝突することがある

### **改善策（設定）**

#### **1. `set iminsert=2` で IME の挙動を改善**
Vim の `.vimrc` に以下を追加：
```vim
set iminsert=2
set imsearch=2
```

#### **2. `imdisable` でノーマルモード時の IME を自動オフ**
```vim
set imdisable
```

#### **3. `fcitx-remote` で Esc を押すと IME を英語に戻す**
Google 日本語入力や `fcitx` を使っている場合、IME をオフにする：
```vim
autocmd InsertLeave * :silent !fcitx-remote -c
```


---

## 2. Linux 風に Vim 内部で日本語を処理する

### **特徴**
- `fcitx`, `ibus`, `uim` などを使用
- Vim 内で IME を制御できる
- IME の影響を最小限に抑えられる

### **メリット**
✅ **Vim のキーバインドを維持しやすい**
- `Ctrl + P/N` の補完機能がスムーズに動作する

✅ **IME の干渉を防げる**
- `Esc` を押したときに遅延が発生しない

✅ **Linux 環境と統一可能**
- Mac 以外でも共通の環境を作れる

### **デメリット**
❌ **Mac では環境構築が必要**
- `fcitx` などの Linux 向けツールを Mac に導入する必要がある

❌ **セットアップが面倒**
- `.vimrc` のカスタマイズが必要

### **設定方法**
Mac で `fcitx` を使う場合：
```sh
brew install fcitx
```

Vim の `.vimrc` で `fcitx` との連携を設定：
```vim
autocmd InsertLeave * :silent !fcitx-remote -c
```

これで `Esc` を押したときに自動で IME がオフになる。

---

## **結論: どちらを選ぶべきか？**

| 方法 | 便利さ | 設定の簡単さ | Vim との相性 | おすすめ度 |
|------|------|------|------|------|
| **Mac の IME を使う** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ✅✅✅✅ |
| **Linux 風の IME (`fcitx` など)** | ⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ | ✅✅ |

### **どちらを選ぶべきか？**
✅ **Mac の IME（Google 日本語入力など）を使うのが最も簡単で一般的**  
✅ **Vim の操作性を最適化したいなら `fcitx-remote` で IME の自動切り替えを設定するのが理想**  
✅ **Linux でも Vim を使うなら `fcitx`, `ibus` などを設定すると快適**  

---

## **おすすめの設定（Mac で IME を快適に使う Vim 設定）**

Vim の `.vimrc` に以下を追加：
```vim
set iminsert=2
set imsearch=2
set imdisable
autocmd InsertLeave * :silent !fcitx-remote -c
```

### **キーバインドで IME 切り替え**
```vim
nnoremap <silent> <C-j> :!fcitx-remote -o<CR>
nnoremap <silent> <C-k> :!fcitx-remote -c<CR>
```
- **`Ctrl + J` で日本語 ON**
- **`Ctrl + K` で日本語 OFF**

---

## **まとめ（2回目）**
✅ **Mac の IME をそのまま使うのが簡単でおすすめ！**  
✅ **Vim を本格的に使うなら `fcitx-remote` で IME の自動切り替えを設定！**  
✅ **Linux でも Vim を使うなら `fcitx`, `ibus` などを活用すると快適！**  

 **結論: Mac の IME を使いつつ ターミナルの中で、`fcitx-remote` を活用？！**
【備忘録】wsl2・Ubuntuのインストール

この環境構築では複数回再起動を行うので、あらかじめ他のタスクは終了させ、参考資料はブックマークに入れておくことを推奨します。


## WSL2のインストール

Windows PowerShell　を管理者として開く

以下のコマンドを実行
コマンドでUbuntuのバージョンを指定する場合は、`-`でバージョンをつなげてスペースがないようにしてください。
```powershell
wsl --install -d Ubuntu-24.04
```
Ubuntuのバージョンは以下から参照してください。
[Ubuntuバージョン一覧](<https://wiki.ubuntu.com/Releases>)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3530065/1105f514-5c3b-0f7f-58ad-a08d09ec96c6.png)
しばらくすると ユーザー名とパスワードを入力するように促されますので、ユーザーを作成してください。
このとき、パスワードは入力しても表示されませんが入力はされているので、気にせずに入力し、エンターで次の項目に進んでください。

`Wellcome to Ubuntu 24.04.2 LTS ...` 
と出てきたら無事インストールが完了したので、マシーンを一度再起動します。

再起動後、もう一度ターミナルを起動しウィンドウ上部にあるタブの下矢印からUbuntu 24.04.6LTSを押下するとUbuntu のタブに切り替わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3530065/070a3506-8b30-089c-24bf-65c4a0a81da6.png)

以上でWSL2とディストリビューションのUbuntuのインストール完了です。

なお、Ubunntuのマウントされたボリュームは`\\wsl.localhost\Ubuntu-20.04`に格納されています。


## ディストリビューションを削除する
powershell で以下のコマンドを実行
```powershell
wsl --list --verbose
```
以下のように現在インストールされているディストリビューションのリストが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3530065/4377c9a2-5280-e61d-a1b8-9be3c7f1f6be.png)

上記で表示された削除したいディストリビューションのNAME 以下のコマンドに当てはめて実行してください。
```powershell
wsl --unregister Ubuntu-20.04
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3530065/21e7863b-fad0-c507-8f60-851193c4a6f3.png)
このように表示されれば削除成功です。
2の補数とコンピューターの演算

## 補数とは
> **ある数に足すとその数の桁からちょうど1桁繰り上がる数**

これだとわからないので例を見ていきます

### 10進数
ある数46に対しての補数は
46に足すとちょうど1桁繰り上がる数なので46は2桁なので
そのちょうど1桁繰り上がると**100**ですので以下のように計算
```
100-46 = 54
```
これが46に対する補数で、その逆に54に対しての補数は46です。
また、この例は**10進数を基準にしている**ので46に対する**10の補数**という

### 2進数
2進数の場合はビットを固定してそれを基準に考えます

ビット数を4ビット固定とした場合、そこからちょうど1桁繰り上がと**10000**の**5桁**です。
ですので、3に対する補数は以下のように計算する
```
 10000
- 0011
-------
  1101
```
これは**2進数を基準**としているので**2の補数**という



## 補数とコンピューターの負の数の扱い

### コンピューターでの負の数の扱い
int型の変数を定義したときほとんどのプログラミング言語は32ビットを確保します。
感覚的に考えると表せる最大値は2^32(4294967296)のように思えます
しかし、これでは負の数も-4294967296まで表すのに32ビット追加で必要になってしまいます。
ですので32ビットを使って正の数も負の数も表すために2^32乗の約半分にした数をそれぞれ表せる正の最大と負の最小にしています。
また、**正の最大を超える場合は負の数**として扱います

ビットを円状にして考えると**最大値を超えると負の値に変わる**ことが視覚的に理解しやすくなります。わかりやすいです。（例として4ビット）

このようにすると先頭のビットを符号として
**0が＋、1がー**を表し残りのビットを整数部と考えることができる

![ビット.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326308/a562ee09-fd79-61df-07ef-0c988bc907d7.png)

### 2の補数と負の数
上記の図で表したように0001の負の数は1111です。
これをなぜコンピューターは負の数として定義しているのか
その理由に関係するのが**2の補数**です。

4ビットを例に考えると
正の数1に対しての補数を求めるとして
補数の定義から4ビットからの一つ桁上がりは10000です。
ですので以下の計算で補数を算出します。
```
  10000
-  0001
-------
   1111
```
+1に対しての補数を求めた結果-1になったのがわかると思います。
これはたまたまでなく2進数の場合、以下のことが言えます。

>ある正の数の補数はその数の負の数になり、ある負の数の補数は
その数の正の数になる

なぜそうなるのかについては、**2の補数の別の求め方と性質**について理解することで納得できます。

### 2の補数の別の求め方
2の補数について求め方として一般的に以下のことが言われています。

> ある数の補数はある数のビットを反転して1を足したものである

先ほどの+1の補数を求めた計算で確かめます。
+1は0001でこのビットを反転 -> 1110
反転したビットに1を足す -> 1111
確かに同じ結果が求まりました。
なぜそうなるかは補数の求め方を以下のように工夫するとわかります。
```
  1111
- 0001
------
  1110
+    1
------
  1111
```
10000は1111+1なので以下のように分解します
すると全桁が1になたものから引くので結果的に
ある数の桁が0なら1-0で1
ある数の桁が1なら1-1で0
これはビットを反転しているのと同じことです。
そして残った+1をすることで結果10000-0001をしている

### 補数の性質
> 補数同士を足すと0になる

ビット反転+1をすると1111になったものをまたビット反転+1をすると0001に戻ります
それぞれを足すと
```
0001+1111 = 10000となり、0になってない
```
これは+1に対しての補数は10000-0001で求めていました
ですので、0001+(10000-0001)を計算しているのと同じなので余分な10000が残ったままなのです
よって4ビットオーバーしたものを無視することができ、0000=0になります。

## 2の補数とコンピューターでの演算の関係
まず、コンピューターがどのように計算するのかコンパイル型言語での計算処理で簡単に説明します。

### 加算処理

```c
int A = 2
int B = 3
int C = A + B
```
#### コンパイル
- コンパイル開始
- コンパイラがAの符号部分(+)と整数リテラル(A)に分解
- コンパイラがBの符号部分(+)と整数リテラル(B)に分解
- Aの型がint（符号付き 32 ビット整数）であることを確認
- Bの型がint（符号付き 32 ビット整数）であることを確認
- CPU の命令セット（x86, ARM など）に対応する機械語を生成
(ここで2進数に変換されて加算処理するようなコードを生成)
- 生成された命令をバイナリ(2進数)に変換
- 結果をメモリに格納
- コンパイル完了

#### コード実行
- コンパイルしたコードを実行
- OS がプログラムをメモリにロード
- CPUが機械語を順番に読み取り、その命令によっていメモリを操作して計算を行う

### 減算処理

```c
int A = 2
int B = 3
int C = B - A
```
B + (-A)として加算処理に変換します
後の基本手順は加算とほとんど同じです。
ただし、CPU の命令セット（x86, ARM など）に対応する機械語を生成する部分で以下の工程が追加されます。

- -Aを求めるためにAの**2の補数**を求める

この工程により求めた数とBとで加算処理をする

```
つまりコンピューターでは減算処理は2の補数を使い加算処理として計算する
```
このメリットは
- 2の補数はビット反転+1と機械的にもとまるので計算が楽
- 減算処理を加算処理にできることで回路をそれように作らなくてよくなるので
ハードウェアーの設計が簡単になる

## まとめ
- 補数とはある数に足すとちょうど一つ桁上りする数
- 2進数の補数を2の補数という
- 2の補数は対象の数の符号が反転したものとなる
- ある数とその2の補数を足すと桁溢れになり、結果が0になる
- ある数の2の補数はその数のビット反転+1
- コンピューターは2の補数を使うことでマイナスの計算を加算処理にする
- 減算処理を加算処理にすることでハードウェアーの設計が簡単
reclineのバージョンが0.0.1となってしまう問題への対処

## はじめに
ここ最近、私はreClineを好んで使っていました。
しかし、途中からファイルが参照できなくなってしまいました。(これは今回の内容とは異なる問題です)
そこで、バージョンを上げれば解消するかと思い、リポジトリの更新と再インストールを実施しました。
結果、以下問題が発生しました。

## 問題
https://github.com/julesmons/recline.git
* 上記リポジトリでは、バージョンが0.0.1となってしまう
* 他のバージョンがどのブランチにも存在しない

## 解消法
とても簡単です。以下、リポジトリを使用します。
古いブランチの退避にしかならないので、時間が経てば上記リポジトリを使う日が来ると思いますので、
それまでの一時対応となります。
https://github.com/julesmons/recline-legacy.git

## 終わりに
上記リポジトリに気付いている方は多いかもしれませんが、自分と同じ所で悩んでいる方の助けになればと思い記事にしました。
os.Open自体のオーバーヘッドについて

最近、大学のサークルの人たちとGoを使ってのDB自作を始めました。
参考にしているのはこちらの本です：

https://link.springer.com/book/10.1007/978-3-030-33836-7

この本は、実際に簡単なDBの実装を追いながらデータベースの実装や中身の仕組みについて学んでいくという内容になっており、Javaによるサンプルコードも公開されています。
これを参考にしながらGoで実装していこうという感じです。

# 疑問

ストレージ周りの操作に関する部分にて、参考にしている本の実装が、`Open`したファイルを`Close`せずに使い回すというものになっていました。

ここで一つ疑問が湧きました。`os.File`は、Openしたとてそのファイルの内容がメモリに読み込まれるわけではありません。実際に読むためには`Read`が必要なはずです。
ということはつまり、`os.File`はファイルへの参照を持っているだけであり、ファイルアクセスに伴うオーバーヘッドはOpen/Close操作ではほぼ発生しないはずです。
だというのに、本の提供する実装では`os.File`に対応するオブジェクトを`Close`せずに使いまわしています。
本当にこのコードに意味はあるのでしょうか？

# 仮説と検証

意味のない実装が本に載るわけがありません。
きっと`os.Open`はそれなりに重い操作で、それを回避するためにこういった実装になっているのでしょう。
というわけで、ファイルを読むたびに`os.Open`と`os.Close`をするコード、`os.Open`したまま繰り返しファイルを読むコードを動かして比較してみることにしました。

検証に使ったのは以下のコードです：

```go
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	iteration:=100000
	buf := make([]byte, 1)

	start := time.Now()
	for i:=0; i<iteration; i++ {
		f, _ := os.Open("test.txt")
		f.Read(buf)
		f.Close()
	}
	fmt.Printf("open/close, for %v times: %vms\n", iteration, time.Since(start).Milliseconds())

	start = time.Now()
	f, _ := os.Open("test.txt")
	for i:=0; i<iteration; i++ {
		f.Seek(0,0) // 毎回ファイルの頭から読み始めるため
		f.Read(buf)
	}
	f.Close()
	fmt.Printf("keep opened, for %v times: %vms\n", iteration, time.Since(start).Milliseconds())
}

```

これを手元のUbuntuで動かしてみると、結果として以下のような出力が得られました：

```shell-session
$ go run main.go
open/close, for 100000 times: 436ms
keep opened, for 100000 times: 73ms
```

というわけで、10万回ファイルを読む場合について、その都度ファイルをOpenしてCloseする場合には436ms、一度Openしたファイルをそのまま使用する場合には73msと、およそ6倍ほど速くなることが判明しました。
それなりにos.Openは重いようです。

# 備考

Unixでのgoの実装では、`File`はファイルディスクリプタを保持する実装になるようです。

```go:go-1.23/src/os/types.go
type File struct {
	*file // os specific
}
```

```go:go-1.23/src/os/file_unix.go
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
// to close the wrong file descriptor.
type file struct {
	pfd         poll.FD
	name        string
	dirinfo     atomic.Pointer[dirInfo] // nil unless directory being read
	nonblock    bool                    // whether we set nonblocking mode
	stdoutOrErr bool                    // whether this is stdout or stderr
	appendMode  bool                    // whether file is opened for appending
}
```

```go:go-1.23/src/internal/poll/fd_unix.go
// FD is a file descriptor. The net and os packages use this type as a
// field of a larger type representing a network connection or OS file.
type FD struct {
...
```

ということは、今回の結果を加味すると、FDの取得にある程度のオーバーヘッドがあるという感じなんですかね。
📚 LeetCode - 88. Merge Sorted Array 2つのソート済み配列をマージする

# 🎯 問題概要
**💡 LeetCode 88: Merge Sorted Array**  
2つの **ソート済み配列** `nums1` と `nums2` を **1つにマージ** し、`nums1` に上書きする問題。

## 📝 入力
```python
nums1 = [1,2,3,0,0,0]  # m = 3
nums2 = [2,5,6]  # n = 3
```
**✅ 期待される出力**
```python
nums1 = [1,2,2,3,5,6]
```
**❗ ルール**
- `nums1` の後半 `n` 個は **空きスペース (`0`)** → ここに `nums2` をマージ！
- **新しい配列を作らずに、`nums1` を直接変更すること！**  

---

# 🚀 3つのアプローチ
| アプローチ | 時間計算量 | 空間計算量 | メリット | デメリット |
|-----------|-----------|-----------|----------|-----------|
| **Approach 1:** ソートを使う | **O((m+n) log(m+n))** | **O(1)** | 簡単で直感的 | ソートの計算コストが高い |
| **Approach 2:** 前からマージ | **O(m + n)** | **O(m)** | ソートせず効率的にマージできる | `nums1_copy` の追加メモリを使う |
| **Approach 3:** **後ろからマージ（最適解）** ✅ | **O(m + n)** | **O(1)** | 追加メモリ不要で最も効率的！ | 少し実装が難しい |

---

# 📝 Approach 1: ソートを使う方法
### 💡 アイデア
1. `nums2` の値を `nums1` の空きスペース (`0` の部分) にコピーする。
2. `nums1` 全体を **ソート** すればOK！

### 📌 実装
```python
from typing import List

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        # nums2 の要素を nums1 の空きスペースにコピー
        for i in range(n):
            nums1[m + i] = nums2[i]
        
        # nums1 をソート
        nums1.sort()
```

### ⚡ 計算量
- **時間計算量：O((m+n) log(m+n))** → `.sort()` のコストが高い
- **空間計算量：O(1)** → 追加の配列を作らない

### ✅ メリット
✔ シンプルで直感的  
✔ `sort()` を使うだけで簡単  

### ❌ デメリット
✖ **ソートの計算コストが高い**（最適ではない）  
✖ すでに **ソート済み** のリストなのに、無駄な処理をしている  

---

# 📝 Approach 2: 2つのポインタを使って前からマージ
### 💡 アイデア
1. `nums1_copy` を作成し、最初の `m` 個をコピー
2. `nums1_copy` と `nums2` を **2つのポインタを使って前からマージ**
3. **小さい方の要素を `nums1` に入れていく**

### 📌 実装
```python
from typing import List

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        # nums1 の m 個の要素をコピー
        nums1_copy = nums1[:m]

        # 2つのポインタを用意
        p1 = 0  # nums1_copy のポインタ
        p2 = 0  # nums2 のポインタ

        # nums1 を上書きしながら統合する
        for p in range(n + m):
            if p2 >= n or (p1 < m and nums1_copy[p1] <= nums2[p2]):
                nums1[p] = nums1_copy[p1]
                p1 += 1
            else:
                nums1[p] = nums2[p2]
                p2 += 1
```

### ⚡ 計算量
- **時間計算量：O(m + n)** → 各要素を 1 回ずつ処理するだけ
- **空間計算量：O(m)** → `nums1_copy` を作るためのメモリを使用

### ✅ メリット
✔ **ソートしなくても速い！**  
✔ **O(m + n) の高速処理**  

### ❌ デメリット
✖ **`nums1_copy` を作るのでメモリを追加で使う（O(m)）**  

---

# 📝 Approach 3: 後ろからマージ（最適解！）
### 💡 アイデア
- `nums1` の後ろにある **空きスペース (`0`)** を活用！
- **後ろから大きい値を埋めていく** ことで、メモリを追加で使わずに済む！

### 📌 実装
```python
from typing import List

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        # ポインタを3つ用意
        p1 = m - 1  # nums1 のデータ部分の最後の位置
        p2 = n - 1  # nums2 の最後の位置
        p = m + n - 1  # nums1 の最後のインデックス

        # 後ろから比較しながら埋める
        for p in range(m + n - 1, -1, -1):
            if p2 < 0:
                break
            if p1 >= 0 and nums1[p1] > nums2[p2]:
                nums1[p] = nums1[p1]
                p1 -= 1
            else:
                nums1[p] = nums2[p2]
                p2 -= 1
```

### ✅ まとめ
- **最速 O(m + n)！**
- **追加メモリを使わない（O(1）で済む！）**

🙌 **参考になったら、いいね＆シェアよろしく** 🚀🔥
実務+Udemy＆書籍の学習法

## 前提

実務で扱う知識の学習方法について説明する。

### 対象読者

- 1〜3 年目の若手エンジニア

## 学習サイクル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074001/fe69a3a5-8fc6-de1c-e684-6c3aecd91db2.png)

Udemy、実務経験、書籍の順で学習する。  
実務経験と書籍の学習は繰り返し実施する。

以降は各学習項目の目的と個人的に感じたメリット・デメリットを説明する。

### Udemy

**目的**

- 最低限の知識を身につける
  - 全部やる必要はなく、時間をかけすぎない

**メリット**

- 学習コストが比較的低い
- 初心者向けのコースは環境構築の手順も丁寧に解説されていることが多い

※公式のチュートリアルをやるべきという人もいるが、若手エンジニアにとっては少しハードルが高い。

**デメリット**

- 動画を進めていくとできた気になる・知識がついた気になって満足してしまう
  - 動画を一周しただけで実務で使えるスキルは身につかない
- 古くなった情報や、実践的な内容が少ないコースもあるので注意が必要
  - コース選びはレビューを参考に慎重に行う

### 実務経験

**目的**

- 業務を通して知識を深め、実践的なスキルを習得する

**メリット**

- 必要に迫られて調べる・実践するので必然的に知識が身に付く
- 周りのエンジニアからフィードバックを得られる

**デメリット**

- 部分的な知識のみ身に付く場合がある

### 書籍

**目的**

- 知識を整理する

**メリット**

- Udemy や業務経験で得た断片的な知識を体系的に整理できる
- ある程度知識がある状態なので内容を理解しやすく、知っている内容は読み飛ばすことで速度が上がり、知識の補完もできる
  - 最初に書籍を読むと知らない内容・用語が多く、認知的な負荷が高くなるので読む速度が遅くなったり、途中で挫折する場合がある
- 知識の定着と生協を実感できてモチベーション向上につながる

**デメリット**

- 最新情報が反映されていない可能性もあるため、出版時期を確認する必要がある
- 多少の時間が必要となる

## まとめ

知識を身につける方法として一番早いのは実務経験です。しかし、その前後に Udemy と書籍学習を取り入れることで知識の身につき方が変わり、モチベーションも上がると思います。

## 余談

筆者は結果論からこの学習方法が良いことを発見しました。他の知識の学習にもこの方法を活用したいと思っています。
【ChatGPT】「アクティブリコール」を取り上げて、その手順をPrompt化しました。


　どうも、カーブミラーです。

　今回は、「アクティブリコール」を取り上げて、その手順をPrompt化しました。

:::note info
本記事は、ChatGPT（Plus版）
で行なっております。
画像はありません。あしからず。
:::
　ChatGPT等の動作状況を知らせる
　　OpenAIのステータスページ。
　　　[OpenAIステータス](https://status.openai.com/)
***
　こちらも載せますね。
　　[ChatGPTが使えない？ログインできない・反応しない原因やエラー時の対処法を解説](https://aismiley.co.jp/ai_news/chatgpt-error-resolution-explanation/)
***
　まずは、ニュースです。

　ChatGPTスマホアプリですが、
　　コードブロックの配色が
　　　今まで、背景色の反転でしたが
　　　　背景色に馴染む色合いに
　　　　　変わりました。

　ライトだと黒地に白文字
　ダークだと白地に黒文字
　　でしたが

　ライトだとライトグレー地に黒文字
　ダークだとダークグレー地に白文字
　　になりました。

　カラースキームを
　　切り替えるかどうか
　　　ちと悩み中🤔
***
　次に

　MicrosoftのCopilotスマホアプリに
　　“Think Deeper”なる思考モデルが
　　　組み込まれてました。

　これは、
　　OpenAI o1のことのようです。

　操作は、
　　Prompt入力をはじめると、
　　　送信ボタンの左側に
　　　　“…”が出てきます。

　　これをタップすると、
　　　ボタンが現れ、
　　　　上が“より深く考える”
　　　　下が“通常通り回答します”と
　　　　　表示されます。

　　ここで、上をタップすれば、
　　　“Think Deeper”（OpenAI o1）が
　　　　回答してくれます｡
　　　　　三十秒ほど掛かる、と
　　　　　　なっていますが
　　　　　　　それほど待ちません😅

　注意点：
　　OpenAI o1と同じく、
　　　Web検索はできません。
　　　　確認しました。

　　また、画像生成も
　　　できません。
　　　　やろうとしたら
　　　　　アスキーアートでした😅
***
　それから
　　これは少し前からの話ですが、
　　　GoogleのGeminiスマホアプリで
　　　　2.0 Flash expが選択可能に。

　上部中央の
　　モデル選択メニューから
　　　選択できます。

　こちらは、
　　Imagen 3での
　　　描画が可能です。
***
　ではさっそく、【本題】です。

　今回は、
　　「アクティブリコール」を
　　　取り上げて、
　　　　その手順をPrompt化しました。

　下記の記事を参考にしました。
　　[あなたも超優秀といわれる！？「アクティブリコール」とは？](https://carpe-di-em.jp/media/9058)

　「アクティブリコール」とは
　　学習した内容を
　　　何も見ずに思い出すことで、
　　　　記憶の定着を
　　　　　強化する勉強法です。

　脳の神経回路を活性化させ、
　　記憶を深く定着させます。

　暗記科目に効果的で、
　　短時間で効率的に実践できるため、
　　　記憶力を高めたい人に
　　　　おすすめです。

　仕事でも勉強でも
　　暗記が必要な項目は
　　　意外と多いものです。

　記事では、
　　以下の手順で紹介しています。

　1. 情報のインプット
　2. 記憶のアウトプット
　3. 確認と復習
　4. 繰り返し
　5. 間隔を空けた復習

　この方法を繰り返すことで、
　　学習内容のアウトプットの機会が
　　　増え、情報が頭の中で整理され、
　　　　試験や模試で必要なときに
　　　　　素早く引き出せるようになる｡
***
　これを
　　Prompt化したのが
　　　こちらです。

　＊＊＊に記憶したいことを
　　書き入れ、送信してください。
```Text:アクティブリコールでの学習方法Prompt
以下の手順に従って、学習内容「{学習内容}」をアクティブリコールで定着させましょう。  

学習内容「＊＊＊」

1. **インプット（理解を深める）**  
   - まず、「{学習内容}」について教科書やノートを読んで理解する。  
   - 重要なポイントを簡単にまとめる。  

2. **アクティブリコール（思い出す）**  
   - 教材を見ずに、白紙に「{学習内容}」について知っていることを書き出す。  
   - もしくは、誰かに説明するつもりで声に出して話す。  
   - 自分で「{学習内容}」に関するクイズを作り、答えられるか試す。  

3. **フィードバック（間違えた部分を強化）**  
   - 書いた内容を教材と照らし合わせ、間違いや抜けを確認する。  
   - 間違えた部分を重点的に復習し、なぜ間違えたのかを分析する。  

4. **間隔を空けた復習（定着させる）**  
   - 1日後・3日後・1週間後に再び「{学習内容}」を思い出し、アウトプットする。  
   - フラッシュカードやマインドマップを活用して、記憶を強化する。  

この方法を繰り返すことで、「{学習内容}」を長期記憶に定着させましょう。
```

　こちらを実践する際に
　　必要なものとスケジュールを
　　　出すには、下記のPromptを
　　　　使ってください。
```Text:必要なものとスケジュール出力Prompt
これを実践するために必要なものはなんですか？
また、スケジュールがあればお願いします。
```

　もちろん、
　　出力内容は参考程度。
　　　必要に応じて、
　　　　深堀りしてください。　

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
【合格体験記】AWS DEA試験

こんにちは。この度AWSの[DEA-C01試験](https://aws.amazon.com/jp/certification/certified-data-engineer-associate/)を受験し無事に合格できたため、学習方法などを共有できればと思います。
![試験結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853136/90b57b6b-c99d-7d50-f04f-9e8eeb29bd7b.png)

## 背景
学習開始時の私のAWSに関するレベル感は以下の通りです。
- 以前に[CLF-C02試験](https://aws.amazon.com/jp/certification/certified-cloud-practitioner/)を受験し、AWSサービスの基礎的な知識は押さえていました（本当にサービス名とおおまかな役割を押さえている程度でしたが...）
- 業務で数ヶ月ほどAWS製品の実務経験がありました。シナリオは「S3のデータをGlueでETL処理してRedshiftに格納し、QuickSightでダッシュボード化する」というまさにDEAの典型パターンのものでした

会社の先輩にも、まさに自分たちが普段業務で扱っている内容が出るからとっつきやすいよと勧められました。馴染みやすい領域の試験だったことは感触としてかなり勉強のやりやすさにつながった気がします。
CLFを受けた時は実務経験がほぼゼロで苦戦したので、やはり実際にサービスに触れた経験の有無は学習のハードルを大きく左右するんだなと実感しました。

## 学習方法
#### 学習期間
2週間ほどでした。もともと3週間程度で計画を立てようと考えていましたが、いざテストセンターを予約しようとしたら悉く枠が埋まっていたため、早めに変更しました。（先延ばしにしてもだれてしまいそうだったので）

あまり余裕のないスケジュールにはなってしまいましたが、上記のレベル感以上の学習者であれば合格は可能かと思います。

早めの試験予約が大事だなと実感しました...

#### 教材
以下２つのみを用いました。
- [Cloud License](https://cloud-license.com/)
どの教材を使うべきか悩んでいましたが、会社の先輩にも「これやっておけば無双できるよ」と勧められ使用しました。アソシエイト資格までを網羅しているベーシックプラン（4,080円/3ヶ月）に課金しました。
1セット7問で構成されているので取り組みやすく、計画にも落とし込みやすかったです。記事投稿時点では全23セットまであり、3周ほど繰り返して全問正当になるまで繰り返しました。

- [Udemy模擬試験](https://www.udemy.com/course/dea-c01-2024aws/)
Cloud Licenseのみでは問題を覚えてしまっていたため、初見問題にも慣れる目的で購入しました。受験日3日前から模擬試験2回分を実施し、Cloud Licenseでは触れられていなかった部分を補完したり、違う聞かれ方のパターンに慣れることができました。

## 結果
結果的には上記の学習期間、教材で合格することができました。
先輩のアドバイス通り、確かにCloud Licenseの問題に類似したものが多い印象でした。
まだ若い試験で問題パターンも限られているという点で、Cloud Licenseをやりこむことが試験の合格に直結するのかなと感じました。

また、試験を通じてGlue, Athena, Redshiftなどの細かな機能について知見を広げることができました。実務でも使う機能は限られていたので、左ペインにこんな機能あったのかというものが多かったです。
実務では直近でデータカタログとAthenaを使う機会があり、今までイメージが曖昧だったこれらの理解を深められた点はタイムリーに役だったなと感じました。

データ関係はホットな領域な上、DEA試験は資格としてはとても取りやすい部類だと思うのでおすすめです！

##
今回は以上になります。最後までお読みいただきありがとうございました！
PMBOK原理・原則：スチュワードシップを学ぶ

PMBOKにおけるスチュワードシップについて整理しました🔍
プロジェクトマネジャーに求められる3つの行動：
・責任感を持った行動
・信頼できる行動
・リソースの適切な利用
シンプルですが、実践が大切ですね。

![マインドマップ (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/5e6a8aaf-8d95-7fe5-c71c-9488c1a23aa1.png)


## スチュワードシップとは？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/6cf2bcf4-9921-c7e3-a281-12090ab173fe.png)

スチュワードシップは、プロジェクトにおいて以下の3つの要素を含みます：

- **責任感を持った行動**  
  プロジェクトの成果に対して責任を持ち、誠実に行動する。
  
- **信頼できる行動**  
  ステークホルダーやチームメンバーから信頼される行動を取る。
  
- **リソースの適切な利用**  
  プロジェクトで使われるリソース（予算、時間、人員など）を効果的かつ公正に活用する。

---

## 具体例：ソフトウェア開発プロジェクト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/1a51aa62-b949-3628-5ea0-6c21d8853302.png)

### 背景
ある企業が新しい業務システムを開発するプロジェクトを立ち上げました。  
プロジェクトマネジャーのAさんは、開発チーム10名を率いています。予算と納期は限られており、要件の追加が発生すると影響が大きいと予測されます。

### 問題の発生
開発中に顧客から新しい機能の追加依頼がありました。  
この要件は元々のスコープには含まれておらず、追加するとコストやスケジュールに大きな影響を与える可能性があります。

### スチュワードシップの発揮

1. **透明性のある情報提供**
   - Aさんは、要件追加による影響（2週間の納期遅れと50万円の追加費用）を正直にチームと顧客に伝えました。

2. **責任範囲の明確化**
   - 追加費用の負担を顧客側がすることを明確にし、誰が何をするべきかを明文化しました。

3. **リソースの最適化**
   - スケジュールとリソース配分を再調整し、効率的にプロジェクトを進める方法を選びました。

---

## 学べること

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/f977ea59-046b-f42e-35e4-c95fab7e1731.png)

- **透明性と信頼の構築**
  Aさんが情報を隠さず提供したことで、チームと顧客との信頼関係が強化されました。

- **責任を明確にすることの重要性**
  追加要件に伴う責任を明確にしたことで、混乱を避け、プロジェクトがスムーズに進行しました。

- **リソースを有効活用する**
  限られたリソースを最適に使うことで、追加要件に対応しつつ納期を守ることができました。

---

## スチュワードシップを実践するための意識すべきこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/54624f30-3aa9-f920-2534-dfd50f446b98.png)

1. **透明性を大切にする**  
   - プロジェクトに関する情報は隠さず共有し、オープンにコミュニケーションをとる。

2. **責任範囲を明確にする**  
   - 各メンバーの役割と責任を明確にし、適切に責任を分担する。

3. **公正にリソースを配分する**  
   - 予算や人員などのリソースを無駄なく活用し、プロジェクト全体を最適化する。

4. **倫理観を守る**  
   - 誠実で公正な行動を心がけ、短期的な利益ではなく長期的な信頼を重視する。

---

## まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/c68527d8-6555-244f-77d3-b04aaa46400a.png)

スチュワードシップを実践することで、プロジェクトの成功が確実に高まります。  
情報の透明性、責任範囲の明確化、公正なリソース配分などが、信頼と成果を生み出す鍵です。  
これらの原則を実践することで、チーム全体の協力体制が強化され、プロジェクトが円滑に進行します。
【robocopyで失敗】Windowsで削除できないフォルダが発生した際の対処

robocopyというコマンドでコピー元のフォルダAを、フォルダA自身にミラーでコピーしてしまいました。

例として下記のコマンドです。
```
robocopy /MIR "C:\Data\Project" "C:\Data\Project\Backup_%date:~0,4%%date:~5,2%%date:~8,2%"
```
「Data\Project」というフォルダを「Data\Project」配下にミラーリングしてしまったという意味です。

結果として「C:\Data\Project\Backup_日付\Project\Backup_日付\....」といった具合に無限にフォルダが出来てしまいました。
それをエクスプローラーで削除しても、削除画面は出ても消えないという事象が発生しました。

## 「自己参照」による問題
Windowsのファイルフォルダ構造で「自己参照」が発生すると、削除や管理が困難になるようです。
パスが260文字（Windowsのパス制限）を超えてしまい、通常の手段ではフォルダが操作できなくなるとのこと。

自身の脳内にある知識では「rmdir」だけだったのですが、残念ながら消えず…。

## PowerShellで強制的に削除

結論として下記コマンドで消えました。

```
Remove-Item -LiteralPath "C:\Data\Project" -Recurse -Force
```
【ローカル SLM 編】機密情報が漏れるのが怖い？じゃあローカルでL(S)LMを動かせばいいじゃない

# 目的
皆さん、生成AIを使っていますよね？
[ChatGPT](https://chatgpt.com/)や[Claude]()といった生成AIが世に出てからもうしばらく経ちました。
今や何をするにも生成AIを活用する環境になってきたかと思います。

その時に課題となってくるのが**機密情報の取り扱い**になるかと思います。
先に上げたブラウザ上やAPI経由で扱う生成AIは、どうしてもやり取りの内容がネット上を経由してしまいます。
加えて、モノによってはやり取りの内容をモデルの学習に使われてしまうのではといった不安もあるかと思います。

:::note warn
機密性での不安から業務活用へ踏み出せない。。。
:::

ここで本日の目的

:::note
### じゃあローカルでL(S)LMを動かせばいいじゃない
:::

# 環境
本日扱うのはこちら
[LM Studio](https://lmstudio.ai/)

# 手順
## LM Studio のインストール
まずローカルで言語モデルを動かすためのツールである[LM Studio](https://lmstudio.ai/)をインストールします。
LM StudioはUIが充実しており、初めてLLMを動かす方にオススメなものになります。

## モデルのダウンロード
アプリ起動後、サイドバーから検索マークを選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/3519886d-a61a-c163-5647-bd66597a64e9.png)

検索窓に[TinySwallow」と入力してください。
いくつか候補が出てきますが、今回はSakanaAIのモデル「**TinySwallow-1.5B-Instruct-GGUF**」をダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/728f3b48-32f6-243b-6f84-c164de444835.png)

:::note
[TinySwallow](https://huggingface.co/collections/SakanaAI/tinyswallow-676cf5e57fff9075b5ddb7ec)とは
sakana.aiが開発した日本語対応済みの小規模言語モデル（SLM）です。
ローカルPCでも十分に動くサイズ感のモデル！
詳細はこちら↓
https://sakana.ai/taid-jp/
:::

# チャットを開始する
インストール完了後、サイドメニューのチャットを開いて下さい。
画面上部の「Select a model to load」より先ほどダウンロードした「**TinySwallow-1.5B-Instruct-GGUF**」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/819e80bb-46ea-fb00-2462-4c620b6acd33.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/1d8442f8-0db4-d1a9-2909-5fa5b753cb54.png)


あとはチャットを使って質問をしてみましょう。
今回利用しているモデルは軽量のものになりますので、ローカルPCでもそれなりの速度で回答を得られるかと思います。
![{F70438F7-52EE-48E2-8BF3-31225522A59A}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/d1aab5e0-dc8c-332f-c62f-3ff3c02f20ec.png)

# まとめ
近年、スマートフォンなどのエッジデバイスで運用できるレベルの小規模言語モデル（SLM）が開発されてきています。
その分、大規模言語モデル（LLM）と比べると性能はまだまだ劣ってしまいますが、現時点でも特定の領域・タスクに特化した活用方法であれば軽量かつ低コストという大きな恩恵が得られるかと思います。

モデルごとに得意・不得意の領域があるので、自分に合ったモデルを見つけつつ是非ローカルでも動かしてみてください。

これで機密性の不安から生成AIは使わないという言い訳はできなくなりましたね。


# 仲間を募集しています！

ARIではエンジニア・ITコンサルタント・PM職全方位で仲間を募集しております。
カジュアル面談、随時受付中です！
ご興味ある方はこちらをご覧ください。

https://note.com/ari_hr/n/n4aed9ba75421
【競技プログラミング】AtCoder Beginner Contest 360_C問題

# 問題
https://atcoder.jp/contests/abc360/tasks/abc360_c

# 既存投稿一覧ページへのリンク
[一覧ページ](https://qiita.com/o_chan_t/items/fc759695acfaef8df2cc)


# 解法手順1

1. 入力を受け取る：
   - N（箱と荷物の数）
   - A（各荷物が最初に入っている箱の番号）
   - W（各荷物の重さ）

2. 結果を格納する変数 ret を 0 で初期化する。

3. 各箱に入っている荷物の最大重さを記録する配列 boxes を、長さ N で 0 で初期化する。

4. 各荷物について以下の処理を行う：
   - 荷物が元々入っている箱の番号 a を取得する（0-indexedに調整）。
   - 荷物の重さ w を取得する。
   - min(boxes[a], w) を ret に加算する。これが移動のコストとなる。
   - boxes[a] を max(boxes[a], w) で更新する。これにより、箱 a に入っている最大の重さを記録する。

5. 最終的な ret の値を出力する。これが求める最小コストとなる。


# ACコード1
```python:ac.py
import logging

def setup_logger(debug_mode):
    logger = logging.getLogger(__name__)
    if not logger.handlers:  # ハンドラが存在しない場合のみ追加
        logger.setLevel(logging.DEBUG if debug_mode else logging.INFO)
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        
        file_handler = logging.FileHandler('program_trace.log', encoding="utf8")
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
    
    return logger

def io_func():
    # 入力を受け取る
    N = int(input())  # 箱と荷物の数
    A = list(map(int, input().split()))  # 各荷物が最初に入っている箱の番号
    W = list(map(int, input().split()))  # 各荷物の重さ
    return N, A, W

def solve(N, A, W, logger):
    logger.debug("処理を開始します")
    logger.debug(f"N:: (={N}), A: (={A}), W: (={W})")
    
    # 結果を格納する変数を初期化
    ret = 0
    logger.debug(f"結果変数 ret を {ret} で初期化しました")
    
    # 各箱に入っている荷物の最大重さを記録する配列を初期化
    boxes = [0] * N
    logger.debug(f"boxes 配列を長さ {N} で初期化しました: {boxes}")
    
    # 各荷物について処理を行う
    for i, a in enumerate(A):
        a -= 1  # 0-indexedに調整
        w = W[i]
        logger.debug(f"荷物 {i+1}: 箱番号 {a+1}, 重さ {w}")
        
        # 移動コストを計算し、結果に加算
        ret += min(boxes[a], w)
        logger.debug(f"移動コスト {min(boxes[a], w)}(min(boxes[{a}](={boxes[a]}), {w})) を ret に加算しました。現在の ret: {ret}")
        
        # 箱の最大重さを更新
        boxes[a] = max(boxes[a], w)
        logger.debug(f"箱 {a+1} の最大重さを {boxes[a]}(boxes[{a}]) に更新しました")
        logger.debug(f"boxes: {boxes}")
    
    logger.debug(f"全ての処理が完了しました。最終的な ret: {ret}")
    return ret

def main():
    logger = setup_logger(debug_mode=True)
    N, A, W = io_func()
    result = solve(N, A, W, logger)
    print(result)

if __name__ == "__main__":
    main()

###
# N: 箱と荷物の数
# A: 各荷物が最初に入っている箱の番号のリスト
# W: 各荷物の重さのリスト
# ret: 最小コストを格納する変数
# boxes: 各箱に入っている荷物の最大重さを記録する配列

# 1. io_func関数:
#    - 標準入力から N, A, W を読み取る
#    - 読み取った値を返す
# 2. solve関数:
#    - 引数として N, A, W, logger を受け取る
#    - ret を 0 で初期化
#    - boxes を長さ N の 0 で初期化された配列として作成
#    - A と W をイテレートし、各荷物について:
#      - 箱番号を 0-indexed に調整
#      - 移動コスト（現在の箱の最大重さと荷物の重さの小さい方）を ret に加算
#      - 箱の最大重さを更新
#    - 最終的な ret を返す
# 3. main関数:
#    - logger を設定
#    - io_func を呼び出して入力を取得
#    - solve 関数を呼び出して結果を計算
#    - 結果を出力

```

## メモ

各箱のなかで最大の重さであれば移動せず留まっていて良い。
「エンジニアリングマネージャーの仕事」を読んで　その2

## はじめに
James Stanier著「エンジニアリングマネージャーの仕事」を読んで私が印象に残ったことをメモがわりに、少しずつアウトプットします。

https://www.oreilly.co.jp/books/9784873119946/

## 2章 まずは自分を管理しよう
### 序文
- プログラマーは生産性を最適化するために、ほとんどの時間をフロー状態で過ごしたいと考える。
    - 😄 同感、そうあるべき
- マネージャーは緊急の割り込み、本番環境の問題、来訪者からランチの誘いなどにより予定していた計画が台無しになることも。**自身が不利益を被りカオスに対処してまでも、他の人たちの生産性を高めることがゴール**。それ本当？
    - 🧐 やむなしと思ってたけどなぁ・・・ 何か策はあるのか？読み進めよう
### 2.1　整理整頓しよう！
マネージャーはメール・DM・対面での会話・ミーティング・あらゆる情報があちこちから殺到する。
よって頭のあかに止める情報をなるべく小さくすることが重要、そのための整理整頓。
- カレンダー
「他の人とのミーチング」「ランチや外出や通院などあなたに予定があることを示す活動」「集中したいときに予定を入れられないようにするための時間枠」を書くようにする。
    - 👍 うん、これはできてる
    - 関係者全体でツールを共有してるのが大前提だな。宣伝みたいで気が引けるが、うちは協業さん含めてこれでスケジュール共有してる。

https://conne.genbasupport.com/

- ToDoリスト
タスクの整理整頓、優先順位付けに。あなたのタスクがある唯一の場所であるべき。
    - 👍 これもできてる
    - Notionを利用、過去に色々試した結果、自分に一番合ってる方法
        - タスクが発生したらチェックボックス付きのリストに追加
        - そのタスクが終了したらチェックをつける
        - その日の終わりに、当該ページを複製して翌日用のページを作成、終了してるタスクは削除しておく
    - 誰にも見せない殴り書きの場所。と決めておくのが重要と個人的には考えている。
    <br/>
- メール受信箱
「メッセージを受け取る主要ソースにする」「完了したものはアーカイブにする」「メールを絶対に削除しない」「読まない定期購読は解除」「重要なメッセージに対するルールを作る」
    - 👍 概ねできてる
    - 特にアーカイブすることは重要と思う。これによって認知負荷がずいぶん下がることを実感。
    - といいつつ、最近放置してるものも増えてきたのでこれを機に一掃、すっきり。
    <br/>
- 情報を記録する場所
目の前にPCがないときのメモ手段を決めておく。
    - 👍 できてる
    - スマホからNotionのタスクリストに直接追加するか、前出の「現場クラウド Conne」のマイスペースに殴り書き


ここまでは大丈夫そう。なので2.2章以降に課題があるのだろう。
ということで、また次回 m(_ _)m
サイバー攻撃におけるコネクトバック通信について

## 前提
コネクトバック通信とは、内部ネットワークの端末が主体的に外部サーバーに接続する手法を一般的に表すものですが、この記事では特にサイバー攻撃を目的として行われるコネクトバック通信について書いています。

## コネクトバック通信とは？
サイバー攻撃を目的として行われるコネクトバック通信（Reverse Connection / Reverse Shell） は、マルウェアなどに感染した内部ネットワークにある端末（被害者のPCなど）から、攻撃者のサーバーに対して接続を行う通信手法です。

**通常、外部から内部ネットワークのマシンに直接接続すること（インバウンド通信）は、ファイアウォール（FW）やネットワーク設定によってブロックされます。** 
しかし、コネクトバック通信を利用すると、内部から外部への通信（アウトバンド通信）を経由して、攻撃者が内部マシンを遠隔操作できるようになります。

## 一般的なファイアウォールの動作
企業や個人のネットワークでは、FWが以下のようなルールで動作することが多いです。  

**内部から外部への通信（アウトバウンド通信）は許可**  
**外部から内部への通信（インバウンド通信）は制限またはブロック**  

例えば：
- **内部PC → インターネット（Webサイト、API通信など）** → **許可される**
- **外部サーバー → 内部PC**（リモートシェルやサーバーへの接続） → **ブロックされる**

これは、外部からの不正アクセスを防ぐための基本的なセキュリティ対策です。
※ 内部から外部への通信を許可する理由は、Web、メール、クラウドといった業務上必要となる外部との通信があるため


## コネクトバック通信のしくみ
攻撃者がマルウェアに感染した内部ネットワーク内のマシンを遠隔操作したい場合、上記のようなFWの設定があると**外部から直接アクセスできない**ため、SSHなどによる通常のリモート接続は使えません。 

そこで、**「感染した内部マシンが自ら攻撃者のサーバーに接続する」** ことで、FWのルールを回避します。

これがコネクトバック通信です。
### 具体的な手順
1. 攻撃者のサーバーで待ち受け（リスナーを起動）
2. 内部マシン（感染したPCなど）から攻撃者のサーバーに接続
   → **内部からのアウトバウンド通信なので、FWはブロックしない**。
3. 接続が確立されると、攻撃者はシェルを操作できる
   → これにより攻撃者はFWの内側に侵入し、内部マシンを自由に操作できる

## **対策**
このような攻撃を防ぐためには、以下のような対策が有効のようです。
- そもそも内部PCなどがマルウェアに感染しないよう対策する
- 未許可の外部サーバーとの通信を禁止する
- ネットワークの通信ログを監視して異常な通信を検知する

## **まとめ**
応用情報技術者試験の学習をしていて、コネクトバック通信に関する問題が出題されました。FWなどネットワークに関する知識があまりなく、コネクトバック通信を使うことでFWをすり抜けられる理屈を知りたくて調べてみました。
最後まで読んでくださりありがとうございました。
Cドライブ肥大化が止まらない

お金もないCドライブの空き容量もない人
せめてDドライブが空いてるなら
緊急手術です（自己責任です）
だいたい移動しちゃいけないファイルが肥大化している
でも移動できるのもある、ならシンボリックリンク（ググれ）で
移動してしまえ（暴論）
以下に参考を張っておきますが、くれぐれも自己責任で使ってね♡



``` cToD_Drive_Move_And_Simboliclink.ps1
# 注意: このスクリプトは管理者権限で実行してください。

# 移動元と移動先のパス設定
$source = "C:\Users\%Username%\AppData\" # 例としてTempフォルダを移動
$destination = "D:\Users\%Username%\AppData\"

# 移動元ディレクトリの存在チェック
if (-not (Test-Path $source)) {
    Write-Host "エラー: 移動元ディレクトリが存在しません。処理を中止します: $source"
    exit
}

if (-not (Test-Path $destination)) {
    Write-Host "エラー: 移動先ディレクトリが存在しません。処理を中止します: $source"
    exit
}

# 移動元ディレクトリ内のフォルダを取得
$folders = Get-ChildItem -Path $source -Directory

foreach ($folder in $folders) {
    $subFolderName = $folder.Name
    $sourceFolderPath = $folder.FullName
    $destinationFolderPath = Join-Path $destination $subFolderName

    # 移動先ディレクトリがすでに存在する場合、スキップ
    if (Test-Path $destinationFolderPath) {
        Write-Host "移動先ディレクトリが存在します。処理をスキップします: $destinationFolderPath"
        continue
    }

    try {
        # フォルダを移動
        Write-Host "移動中: $sourceFolderPath を $destinationFolderPath に移動します..."
        Move-Item -Path $sourceFolderPath -Destination $destinationFolderPath -ErrorAction Stop

        # 元の場所にシンボリックリンクを作成
        Write-Host "シンボリックリンク作成中: $sourceFolderPath -> $destinationFolderPath"
        New-Item -Path $sourceFolderPath -ItemType SymbolicLink -Target $destinationFolderPath -ErrorAction Stop
    } catch {
        Write-Host "フォルダ '$sourceFolderPath' の移動/リンク作成に失敗しました: $_"
        # エラー情報をログファイルに記録する処理を追加
    }
}
```

※意味を理解して分かる人だけがコードを動かしていいと聖書にあった

Q.壊れた！
A.知らん
REALFORCE R3SC12 のキー入力の問題を解決した話

# 背景

こちらを購入しました。
Amazon | REALFORCE R3S キーボード 有線 テンキーレス 変荷重 日本語配列 ブラック R3SC12 | REALFORCE | パソコン用キーボード 通販
https://www.amazon.co.jp/REALFORCE-%E3%83%AA%E3%82%A2%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B9-%E9%9D%99%E9%9B%BB%E5%AE%B9%E9%87%8F%E7%84%A1%E6%8E%A5%E7%82%B9%E6%96%B9%E5%BC%8F-Windows-R3SC12/dp/B0B3QVKPCN?th=1

# 問題

Macでうまくキー入力されませんでした。
上記、アマゾンのコメント欄にあるように、
> 半角全角キーを押すと「'」と入力されます。「@」や記号が印字されたキーと違うものが入力されてしまいます。

です。
対策として、以下のように書かれています。
> 日本語配列のキーボードが英語配列として認識されております。REALFORCEカスタマーセンターまでお問い合わせください。

# 解決方法

公式サイトにある通り、以下を実行すればよかったです。実施しても特にシステム的に問題なかったです。

> また、改善されない場合には、下記対処方法もお試しください。
Macintosh HD>ライブラリ>Preferences>com.apple.keyboardtype.plist
を削除し、Macを再起動後、再度キーボードアシスタント設定を行ってください。
MSAではなぜリクエストをCommandに変換するのか？

## MSAにおけるUseCaseのインターフェース設計：なぜリクエストをCommandに変換するのか？**  

### **1. はじめに**  
マイクロサービスアーキテクチャ（MSA）において、UseCaseのインターフェース（インバウンドポート）を設計する際に、  
**「コントローラーから受け取ったリクエストをそのまま渡さずに、Commandオブジェクトに変換して渡す」** という設計パターンがよく使われます。  

---

### **2. なぜCommandオブジェクトに変換するのか？**  

#### ✅ 1. UseCase（ビジネスロジック）とWebリクエストのモデルを分離するため  
- コントローラーが受け取る `Request DTO`は、HTTPリクエストの仕様に依存しています。  
- しかし、**UseCaseはHTTPリクエストの形式に依存してはいけません。**  
- そこで、**ビジネスロジックが理解しやすいCommandオブジェクトに変換して渡す**ことで、ユースケースの独立性を保ちます。  

#### ✅ 2. 不必要な依存関係をなくすため  
- `Request DTO` には、Spring MVC などの **Webフレームワークに依存した情報** が含まれることがあります。  
- `UseCase` のインターフェースでこれを直接扱うと、**アプリケーションのアーキテクチャがWebフレームワークに強く依存してしまう** ため、拡張性が低下します。  
- Commandオブジェクトを使用することで、**ユースケースがフレームワークに依存しないクリーンな設計** になります。  

#### ✅ 3. 入力データの責務を明確にするため  
- `RegisterMembershipCommand` のような **明確なオブジェクトを定義することで、必要なデータのみを扱う** ことができます。  
- 例えば、リクエストには `timestamp` や `IPアドレス` など不要なデータが含まれることがありますが、Commandには **ユースケースに必要なデータだけを渡せます。**  

---

### **3. コードで理解する**  

#### **Controller**
```java
@RestController
@RequestMapping("/membership")
@RequiredArgsConstructor
public class MembershipController {
    private final RegisterMembershipUseCase registerMembershipUseCase;

    @PostMapping("/register")
    public ResponseEntity<Void> register(@RequestBody RegisterMembershipRequest request) {
        // 🔹 Request DTO → Commandオブジェクトに変換
        RegisterMembershipCommand command = new RegisterMembershipCommand(request.getUsername(), request.getEmail());

        // 🔹 ユースケースを実行（Requestをそのまま渡さない）
        registerMembershipUseCase.registerMembership(command);

        return ResponseEntity.ok().build();
    }
}
```
**ポイント:**  
- `RegisterMembershipRequest` はWebリクエストのDTO（データ転送オブジェクト）  
- `RegisterMembershipCommand` はビジネスロジック用のCommandオブジェクト  
- **コントローラーは `Request → Command` に変換してからユースケースに渡す**  

---

#### **UseCase Interface**
```java
public interface RegisterMembershipUseCase {
    void registerMembership(RegisterMembershipCommand command);
}
```
**ポイント:**  
- **UseCaseはWebのリクエスト形式に依存しない**  
- Commandオブジェクトを受け取ることで、**どのアダプター（Web、CLI、gRPCなど）からも再利用できる**  

---

#### **Commandオブジェクト**
```java
@Getter
@AllArgsConstructor
public class RegisterMembershipCommand {
    private final String username;
    private final String email;
}
```
**ポイント:**  
- Commandオブジェクトは **純粋なデータ構造** であり、Webのリクエストとは関係ない  
- ユースケースに **必要な情報だけを持たせる**  

---

### **4. まとめ**  

✅ **UseCaseはWebリクエストのDTOに依存しないようにするべき**  
✅ **Commandオブジェクトを使うことで、ユースケースを独立した形で設計できる**  
✅ **フレームワーク依存を避け、アプリケーションの再利用性・保守性を向上させる**
📚 LeetCode - 27. Remove Element 配列の特定の要素をインプレースで削除する方法

# 🎯 問題の概要
与えられた整数配列 `nums` から、特定の整数 `val` をすべて削除してください。  
このとき、**配列の順序は変わってもOK** ですが、**配列自体を新しく作り直さずに（インプレースで）削除** する必要があります。  
最後に、削除後の `nums` の**要素数（val 以外の数）** を返してください。

例えば、次のような配列があるとします：

```
nums = [1, 2, 3, 5, 4]   （削除する数字は 4）
```

この場合、`4` を削除すると `nums = [1, 2, 3, 5]` になり、戻り値は `4` となります。

---

# ✅ 解答の条件
削除後の `nums` について、以下の条件を満たす必要があります：
1. `nums` の最初の `k` 個の要素は、`val` とは異なる値で構成される。
2. `nums` の後半部分（`k` 以降）は重要ではなく、どんな値が入っていてもOK（配列のサイズは考えなくてよい）。
3. `k`（削除後の `nums` の長さ）を返す。

---

# 💡 解決策 1：**二つのポインタを使った方法（Two Pointers）**
### ✨ アルゴリズム
1. `i` を 0 に設定（`i` は `val` 以外の要素を置いていくポジション）。
2. `j` を 0 から `nums.length - 1` まで動かす。
3. `nums[j]` が `val` でない場合：
   - `nums[i] = nums[j]` にして、`i` を進める。
4. `i` が最終的に `val` 以外の要素数 `k` になるので、それを返す。

### 🎯 コード（Python）
```python
from typing import List

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i = 0
        for j in range(len(nums)):
            if nums[j] != val:
                nums[i] = nums[j]
                i += 1
        return i
```

---

# 💡 解決策 2：**後ろから要素を入れ替えて削除する方法**
### ✨ アルゴリズム
1. `i` を 0 に、`n` を配列の長さに設定。
2. `i < n` の間、繰り返し処理する：
   - `nums[i] == val` ならば：
     - **後ろの要素と入れ替える** (`nums[i] = nums[n-1]`)
     - **配列の長さを1つ減らす** (`n -= 1`)
   - そうでなければ `i` を増やす。
3. `n` が新しい要素数（val 以外の数）なので、それを返す。

### 🎯 コード（Python）
```python
from typing import List

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i = 0
        n = len(nums)
        while i < n:
            if nums[i] == val:
                nums[i] = nums[n-1]
                n -= 1
            else:
                i += 1
        return n
```

# 🔥 どちらの方法を選ぶべき？ 🎯
| 方法 | 使うべき場合 | メリット | デメリット |
|------|------------|--------|----------|
| **方法 1（Two Pointers）** | `val` の数が多い | 一定の順序を保ちつつ削除できる | `val` と同じ要素が少ないと無駄な代入が多くなる |
| **方法 2（Swap & Shrink）** | `val` の数が少ない | ループの数を減らせるため、コピー（代入）が減るので処理が速い | 順序が崩れる |

# 🎉 まとめ

✅「順序を崩してもいいなら、後ろから入れ替える方法 2（Swap & Shrink）が良い！」  
✅「順序をなるべく保ちたいなら、前から詰める方法 1（Two Pointers）が便利！」

どちらの方法もメリットがあるので、問題に応じて使い分けよう 🚀🔥
AWS Personalize活用術：有効期限付きアイテムを自動で除外する方法

近年、ECサイトをはじめとした多くのサービスで、ユーザーの行動に基づいたレコメンド機能が活用されています。しかし、期間限定のアイテムや年齢制限のあるアイテムなど、特定の条件下ではレコメンド対象から除外する必要があるケースも少なくありません。
本記事では、AWSのレコメンデーションサービスであるAWS Personalizeを使用し、こうした制限付きアイテムを除外するフィルタ設定の方法について解説します。

# Personalizeのフィルタ設定

## 前提

- AWS Personalizeのレコメンダーまで構築が完了しているものとさせていただきます。
- 今回は、VIDEO_ON_DEMAND ドメインを用いたデータセットで実施しております。
- Interactions/User/Itemのスキーマは下記になります。

【Interactionsのスキーマ】
```
{
	"type": "record",
	"name": "Interactions",
	"namespace": "com.amazonaws.personalize.schema",
	"fields": [
		{
			"name": "USER_ID",
			"type": "string"
		},
		{
			"name": "ITEM_ID",
			"type": "string"
		},
		{
			"name": "TIMESTAMP",
			"type": "long"
		},
		{
			"name": "EVENT_TYPE",
			"type": "string"
		}
	],
	"version": "1.0"
}
```
【Userのスキーマ】
```
{
	"type": "record",
	"name": "Users",
	"namespace": "com.amazonaws.personalize.schema",
	"fields": [
		{
			"name": "USER_ID",
			"type": "string"
		},
		{
			"name": "AGE",
			"type": "long"
		}
	],
	"version": "1.0"
}
```
【Itemのスキーマ】
```
{
	"type": "record",
	"name": "Items",
	"namespace": "com.amazonaws.personalize.schema",
	"fields": [
		{
			"name": "ITEM_ID",
			"type": "string"
		},
		{
			"name": "GENRES",
			"type": "string",
			"categorical": true
		},
		{
			"name": "CREATION_TIMESTAMP",
			"type": "long"
		},
		{
			"name": "EXPIRATION_DATE",
			"type": "long"
		}
	],
	"version": "1.0"
}
```

## フィルタ設定

今回はItemの「EXPIRATION_DATE(有効期限)」が現在時刻よりも古いアイテムを除外するフィルタを設定します。
実際にフィルタを設定した画面が下記となり、Items.EXPIRATION_DATEが現在時刻($current_time)を下回っていれば、除外する(EXCLUDE)としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3790709/47738b45-ea15-c6c5-2186-e8baf6422aa2.png)

# 実行結果

フィルタ適用前は、レコメンドされた25個のアイテムのうち12個が有効期限切れのアイテムでした。
しかし、フィルタを適用したことで、すべてのレコメンドが有効期限内のアイテムに限定され、不要なアイテム表示されることはなくなりました。

|  | フィルタ適用前 | フィルタ適用後 |
|:-----------|------------:|:------------:|
| 有効期限切れアイテムの数|12個|0個|


# 結論

フィルタを適用することで、有効期限切れのアイテムを完全に除外することができました。フィルタの活用は、レコメンドの精度向上に直結します。提供するアイテムやユーザーのニーズに応じて適切にフィルタを設定し、より最適なレコメンド体験を実現していきましょう！