OmniAICreator/Qiita-1.07M huggingface dataset:
AIの基本概念

以下に、Pythonのコードを交えながらAIについてわかりやすく解説する記事を作成しました。この記事では、AIの基本概念から、機械学習や深層学習の具体例まで、段階的に説明します。

---

## **AIとは何か？**
AI（人工知能）は、コンピュータが人間のように「考え、学び、行動」できる技術です。AIは、パターン認識、データ分析、意思決定などのタスクを自動化し、効率的に行うために設計されています。

---

### **AIの基本的な流れ**
AIシステムの基本的な流れは以下の通りです。

1. **データの収集と前処理**: AIモデルの学習に使うデータを用意します。
2. **モデルの構築と学習**: モデルにデータを与えて学習させます。
3. **予測と応用**: 学習したモデルを使って予測や分析を行います。

---

## **Pythonを使った簡単なAIの例**

ここでは、AIの仕組みを具体的に理解するために、Pythonで「手書き数字を分類するAI」を例に説明します。

### 必要なライブラリをインストール
まず、以下のコードでライブラリをインストールします。

```bash
pip install tensorflow matplotlib
```

---

### **1. データの準備**
AIを学習させるために、MNIST（手書き数字データセット）を使用します。

```python
import tensorflow as tf
from tensorflow.keras.datasets import mnist

# MNISTデータセットの読み込み
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# データの正規化（0〜255のピクセル値を0〜1に変換）
x_train = x_train / 255.0
x_test = x_test / 255.0
```

ここでは、手書き数字の画像データを読み込み、AIが効率的に学習できるように正規化しています。

---

### **2. モデルの構築**
次に、簡単なニューラルネットワークを構築します。

```python
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Flatten, Dense

# モデルの定義
model = Sequential([
    Flatten(input_shape=(28, 28)),   # 画像を1次元に変換
    Dense(128, activation='relu'),  # 隠れ層
    Dense(10, activation='softmax') # 出力層
])
```

- **Flatten**: 28x28ピクセルの画像を1次元の配列に変換します。
- **Dense**: 全結合層で、データを処理します。
- **softmax**: 出力を確率分布に変換します。

---

### **3. モデルのコンパイルと学習**
次に、モデルをコンパイルして学習させます。

```python
# モデルのコンパイル
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# モデルの学習
model.fit(x_train, y_train, epochs=5)
```

- **optimizer='adam'**: 最適化アルゴリズム。
- **loss**: モデルの誤差を計算する関数。
- **metrics**: モデルの性能を評価する指標。

---

### **4. モデルの評価**
学習が終わったモデルをテストデータで評価します。

```python
# モデルの評価
test_loss, test_acc = model.evaluate(x_test, y_test)
print(f"テストデータの正解率: {test_acc * 100:.2f}%")
```

---

### **5. 予測の可視化**
学習済みモデルを使って、手書き数字を予測してみましょう。

```python
import matplotlib.pyplot as plt

# テストデータの1つを予測
predictions = model.predict(x_test)
predicted_label = predictions[0].argmax()

# 結果を表示
plt.imshow(x_test[0], cmap='gray')
plt.title(f"予測: {predicted_label}")
plt.show()
```

このコードは、手書き数字の画像を表示し、AIが予測した数字を示します。

---

## **AIの仕組みを簡単に説明**
1. **データの理解**  
   AIは、データを見てパターンを学習します。この例では、手書き数字のピクセルパターンを学習しました。

2. **ニューラルネットワーク**  
   ニューラルネットワークは、層（Layer）を通じてデータを変換し、最終的に結果を出します。

3. **学習と最適化**  
   学習過程では、AIは間違いを修正しながら精度を向上させます。

---

## **AIの応用例**
このようなAI技術は以下のような分野で活用されています。

- **画像認識**: 顔認識、医療診断。
- **自然言語処理**: 翻訳、チャットボット。
- **予測分析**: 売上予測、金融リスク分析。

---

## **まとめ**
この記事では、AIの基本概念とPythonを使った簡単な実装例を紹介しました。AIはデータから学び、人間のように意思決定や予測を行う強力なツールです。Pythonを使えば、初心者でも簡単にAIの仕組みを体験できます。

**次のステップ**として、さらに複雑なモデル（ディープラーニングや自然言語処理）に挑戦してみてください！

参考文献
https://youtu.be/5NgNicANyqM?si=XToj1_-VqcIMvyf_
自分でサイトのフォントをカスタマイズできる機能を作ってみた

## はじめに
ユーザーがフォントを自分で設定できるサイトを作ってみました。

https://font-with-user-select.vercel.app/

![ユーザーがフォントを自由に変えられるサイトのスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267174/bdce45b0-8133-4591-ffa3-9819506bba3f.png)

これは、設定メニューを開くと、フォントの設定ができます。デフォルトではNoto Sans JP,UDフォントを選択するとBIZ UDゴシックに、自分で設定をするを選択すると、入力フォームが出てきます。
入力フォームには、自分がインストールした好きなフォントを入力すると、反映されます。

これで、開発側はユーザーに見せたいデフォルトのフォントを設定、ユーザーは自分が見やすいフォントに設定できます。

## なぜ作ったか

ディスレクシアをご存知でしょうか？

https://www.ncchd.go.jp/hospital/sickness/children/007.html

https://shigoto4you.com/udfont/

ざっくり言うと、文字を読むのが一般的な人よりも難しい方がいらっしゃいます。そんな方々でも読みやすいように、モリサワフォントなどがユニバーサルデザインに配慮したフォント、UDフォントを作成されました。

https://www.morisawa.co.jp/about/news/6706

しかし、フォントって、サイトのデザインでもわりと重要な部分だったりします。全部をUDフォントにしろって言ってしまうと、デザインの自由がなくなってしまいます。でもそのままのフォントだと、見にくいと思うユーザーも出てきます。

そこで、ユーザーが自由に設定できたらいいのではないかという思いやりで簡単に作ってみました。

さらに、UDフォントでも読みにくいっていうユーザーもいるかもしれないです。そういう方にはさらに、自分で好きなフォントをインストールしていただき、設定してもらうと、自分の好きなフォントにカスタマイズできるという機能もつけました。

![フォントを変えた版のサイト](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267174/da4f75a1-6086-6478-17ce-f8ae65944a1a.png)

これは、適当ポエムというフォントを自分のPCにインストールし、サイトに反映しました。特にアップロードなどはしていないです。

https://cktrc.com/tekitoupoem/

また、文字間隔や高さなどの影響で読みにくいと感じる人だっています。文字間隔が何pxだから読みやすいなど、決めつけるとそれ以外の人は見にくくなります。なので、デフォルトを設定して、そこからユーザーが数値をいじれれば、いろんなユーザーに見やすいと思い、作りました。

でも、文字が小さすぎて、大きすぎて読めないというユーザーもいらっしゃいます。その方は、ブラウザのズーム機能で拡大・縮小できるので、それに応じてデザインが崩れなければ不要と考え、設定は設けませんでした。

## どうやって作ったのか

こちらにソースコードがあります。

https://github.com/mu-tomoya/font-with-user-select

自分はReactが得意なのでReactを使って作りましたが、状態管理ができれば別にReact以外でも構わないです。

設定の値をグローバルで状態管理して、メインページの方にその設定を反映させます。

一番の肝は、コードにcss変数を埋め込むことです。

```tsx
import useSettings from "./useSetting";

const MainPage = () => {
  const { font, letterSpacing, lineHeight } = useSettings();
  return (
    <div>
      <main>
        <div
          className="paragraph"
          style={{
            ["--font-family" as string]: font,
            ["--letter-spacing" as string]: `${letterSpacing}px`,
            ["--line-height" as string]: `${lineHeight}`,
          }}
        >
        文章
        </div>
      </main>
    </div>
  );
};

export default MainPage;

```

useSettingsは設定の状態を持っているReact Hooksだと思ってください。このメインページのコンポーネントの中で、styleに直接、`["--font-family"]: font`のように埋め込みます。

そして、CSS側でちゃんとCSS変数を作ってあげます。
```css
:root {
  --font-family: "Noto Sans JP", sans-serif;
  --letter-spacing: 0.1rem;
  --line-height: 1.5;
}

.paragraph {
  font-family: var(--font-family), sans-serif;
  letter-spacing: var(--letter-spacing);
  line-height: var(--line-height);
  margin: 5rem;
}
```
これで、JS側から受け取ったCSS変数をCSS側に反映させることができます。

## 終わりに

つい先日、LETTER RUSHという、手紙が書けるWebアプリを作ってみました。

https://letter-rush.vercel.app/

そこでCSS変数をReactで制御するという技を得ました。わりとこれは便利な手法だなって思いました。ちょっと書き換えれば、ブラウザで設定したフォントを優先するなどできます。

これを利用して、もっとユーザーがある程度自由にフォントを自由にカスタマイズできるサイトが増えたらなと思いました。例え明確な障害をもっていなくとも、文章が読みづらいなどがあるかもしれません。特に、文章がメインのサイトなど、こういうふうなカスタマイズ性を設定ページなどに持たせても良いのではないでしょうか？

ちょっとした優しさ、気遣いの積み重ねが、双方の利益につながるかもしれません。
背景色の明度によってテキストカラーを白黒に変更するJavaScript

## はじめに

Webサイトのデザインにおいて、背景色に応じて適切なテキストカラーを設定することは重要です。この記事では、JavaScriptを使用して背景色の明度を自動判定し、最適なテキストカラー（黒または白）を設定する方法を解説します。

## 実装方法

### 1. 要素の取得

まず、テキストカラーを変更したい要素を取得します。

```javascript
let arrClrYamadus = Array.prototype.slice.call(document.querySelectorAll(".c-yamadu"));
```

### 2. 明度計算関数の実装

背景色の明度を計算する関数を実装します。WCAG 2.0のガイドラインに基づいて相対輝度を計算します。

```javascript
const getColorLuminance = (color) => {
  // RGBに変換
  const getRGB = (color) => {
    const temp = document.createElement('div');
    temp.style.color = color;
    document.body.appendChild(temp);
    const rgb = window.getComputedStyle(temp).color;
    document.body.removeChild(temp);
    return rgb.match(/\d+/g).map(Number);
  };

  // 相対輝度を計算
  const getLuminance = ([r, g, b]) => {
    const [rs, gs, bs] = [r, g, b].map(c => {
      c = c / 255;
      return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
    });
    return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
  };

  return getLuminance(getRGB(color));
};
```

### 3. テキストカラーの設定

計算した明度に基づいて、適切なテキストカラーを設定します。

```javascript
const luminance = getColorLuminance(bgColor);
element.style.color = luminance > 0.55
  ? 'var(--c-text,hsl(223, 6%, 13%))'
  : '#FFF';
```

### 4. イベントリスナーの設定

DOMの読み込み完了時とページロード時に処理を実行します。

```javascript
['DOMContentLoaded', 'load'].forEach((events) => {
  window.addEventListener(events, fnYamaduXANA);
});
```

## 技術的なポイント

1. **相対輝度の計算**: WCAG 2.0に準拠した計算方法を採用し、アクセシビリティに配慮しています。

2. **CSS変数の活用**: テキストカラーにCSS変数を使用することで、テーマ変更にも対応できます。

3. **パフォーマンス**: 一時的なDOM要素を使用してRGB値を取得し、直後に削除することで、メモリ効率を考慮しています。

## まとめ

このスクリプトを使用することで、背景色に応じて適切なテキストカラーが自動的に設定され、可読性の高いUIを実現できます。また、WCAG 2.0に準拠した計算方法を採用することで、アクセシビリティの観点からも信頼性の高い実装となっています。
ディスコードサーバー掲示板を簡易的に作った！

## はじめに
こんちゃっちゃ！れししぐです！
もういつの間にか12月ですね（遅い）
1作目は沼っていつ投稿するかわかりませんが、一応ディスコード関係2作目です。
## 本題
今回はPHPでディスコードのサーバー掲示板を作った話です！

**＜実際に作ったのがこちら＞**
サーバー掲示板サイト：https://discom.42web.io

今は一応誰でも登録できるようになっていますが、何か起きたら新規登録は停止する予定です。
このサイトはphpがメインなんですけど、サーバーデータはMySQLではなく、データベースめんどかったのでテキスト管理です()
セキュリティーなんて皆無です！！！！！！！
だからって変なことするのはやめてね！
（当たり前ですが、日本にはサーバー攻撃等を取り締まる法律があります。）
このサイトではphpでテキストファイルにjson形式で書き込んで保存する簡易的な方法をとっています。
登録されたIDを元にサイトからだけでなく、BOTからもUPできるようになってます。(僕の自作BOTからUP可能　僕の自作botに関してはディスコード関係1作目に書いてあります。)
色々めんどくさくて手抜きですが、ある程度は使えるので使ってくれたら嬉しいです！
## おわり
時間がないので今回はここまで！！
もしかしたら続きを書くかもしれません
それじゃグッバイ！

受験めんどい...........
Linuxにおける「lastlog」とは？

Linuxにおける「`lastlog`」とは、システム上の各ユーザーアカウントについて、**最後に成功したログインの記録**を表示するためのコマンドおよびログファイルです。この情報はセキュリティ監視やシステム運用に役立ちます。

---

### **特徴**

1. **ログの保存場所**
   `lastlog` の情報は、通常 `/var/log/lastlog` ファイルに保存されます。このファイルはバイナリ形式で記録されており、直接読むことはできません。
2. **表示内容**
   各ユーザーアカウントについて以下の情報を表示します。
   - ユーザー名
   - UID（ユーザーID）
   - 最後にログインした日時
   - 最後にログインした端末や接続元（TTY または IP アドレス）
3. **空白の表示**
   ログイン履歴がないユーザーについては、「**Never logged in**」と表示されます。

---

### **使用例**

#### 基本的な使用

```
lastlog
```

#### 出力例

```
Username Port From Latest root tty1 192.168.1.100 Wed Nov 15 10:22:45 +0000 2023 user1 pts/0 203.0.113.5 Tue Nov 14 08:15:30 +0000 2023 user2 tty2 Never logged in
```

---

### **オプション**

1. **特定のユーザーのログイン履歴を確認**
   ```
   lastlog -u [ユーザー名のUID]
   ```
   - `UID` はユーザーに対応するID（通常 `/etc/passwd` に記載されています）。
   - 例:
     ```
     lastlog -u 1001
     ```
     ‌
2. **特定の範囲のUIDに限定**
   ```
   lastlog -t [日数]
   ```
   ‌
   - 指定した日数以内にログインしたユーザーを表示。
   - 例:
     ```
     lastlog -t 30
     ```
     （最後のログインが30日以内のユーザーのみ表示）

---

### **ログファイルの管理**

- **サイズが大きくなる場合**
  多くのユーザーが存在するシステムでは、`/var/log/lastlog` ファイルが非常に大きくなる可能性があります。ファイルをクリアすることでサイズを減らすことができますが、情報が失われるため注意が必要です。
  ```
  > /var/log/lastlog
  ```
  ‌
- **ファイルの再生成**
  必要であれば、`lastlog` ファイルは削除しても再生成されます。ただし、すべての履歴がリセットされます。
  ```
  rm /var/log/lastlog
  touch /var/log/lastlog
  ```

---

### **セキュリティ上の利用例**

1. **ログイン試行の監視**
   未使用アカウントのセキュリティリスクをチェックするために利用できます。
   - ログインしたことがないユーザーや、最後のログインが長期間前のユーザーをリストアップし、不要なアカウントを無効化または削除する。
2. **異常検出**
   特定の時期に不正アクセスが疑われる場合に、ログイン履歴を確認することで、不正に使用されたアカウントを特定できます。

---

### **注意点**

- `lastlog` の出力はシステムの全ユーザーについて表示されるため、ユーザー数が多い場合は大量の情報が表示されます。必要に応じて `grep` などを併用してください。
- `/var/log/lastlog` ファイルが壊れている場合、出力結果が不正確になることがあります。この場合はファイルを削除して再生成してください。

---

これにより、`lastlog` はシステム上のユーザー活動を追跡し、管理する上で重要なツールとなります。
WSL にホストの IP アドレスを使用できるようにする方法

　この記事では Hyper-V、仮想インターフェースを使い WSL 内で使用するネットワークがホストの IP アドレスとして利用できるようにする方法を解説します。そのためには以下の記事を事前に読んで、作業を終えていることが必要です。

- VScode をインストール

https://qiita.com/GAI-313/items/f3d4722ebeda5ea195d1

- Windows 11 Home で Hyper-V を有効にする

https://qiita.com/GAI-313/items/a3ac77676a513d74e2a6

- 仮想インターフェースを Hyper-V で作成する

https://qiita.com/GAI-313/items/0f734c0d06b55d58b08b

# .wslconfig を作成する
 VScode を開き、`.wslconfig` を作成します。VSCode を起動して、「ファイル」タブの「新しいファイル」をクリックして、新規ファイルを作成します。

> キーボードショーっとカットキーで ***「Control + ALT + Windows + N」*** で素早く新規ファイル作成することができます。
<img src="https://i.imgur.com/lO5feTL.png" />

　するとこのようにファイル名を入力するバーが表示されるので、ここに `.wslconfig` という名前のファイルを作成してください。
<img src='https://i.imgur.com/wnq0RXU.jpeg'/>

　作成された `.wslconfig` に以下のコードを貼り付けてください。
```
[wsl2]
networkingMode=bridged
vmSwitch=vm_ethenet
dhcp=true
localhostForwarding=True
```
::: note warn
## `vmSwitch` の名前が `vm_ethenet` ではない場合
　この記事は [仮想インターフェースを Hyper-V で作成する](https://qiita.com/GAI-313/items/0f734c0d06b55d58b08b) を事前に読んで背セットアップしていることを前提に書かれています。[仮想インターフェースを Hyper-V で作成する](https://qiita.com/GAI-313/items/0f734c0d06b55d58b08b)  では `vm_ethenet` というプロパティ名で仮想インターフェースを作るように記述されています。もし、異なる名前の仮想インターフェースをすでに用意しているか、作成した場合は、上記のコードの `vmSwitch` に挿入される値をそのインターフェースプロパティ名に変更してください。
:::

<img width=5%/><img width=45% src='https://i.imgur.com/SwujlIy.jpeg'/><img width=5%/><img width=45% src='https://i.imgur.com/HgUAdz5.jpeg'/>

　そうしたら、VScode で編集した内容を更新するために「Control + S」による保存をしてください。変更が保存されていない場合、ファイル名横に白い丸が表示されます。
<img width=5%/><img width=45% src='https://i.imgur.com/nT4qxis.jpeg'/><img width=5%/><img width=45% src='https://i.imgur.com/k73gr4z.jpeg'/>
【AWS】Amazon CloudFrontで静的IPアドレスがサポートされた

AWSの最新情報（2024/11/21 JST）を眺めているとこんなものが。
#### Amazon CloudFront now supports Anycast Static IPs

https://aws.amazon.com/about-aws/whats-new/2024/11/amazon-cloudfront-anycast-static-ips/

CloudFrontで静的IPアドレスがサポートされたみたいですね。

:::note Anycastについて
Anycast IPは複数のインターフェースに割り当てられるIPアドレス。
経路制御によって送信元から近いインターフェースに向けて通信するよ。

[IP Anycast（アイピーエニーキャスト）](https://jprs.jp/glossary/index.php?ID=0108)
[エニーキャストアドレス(Anycast Address)とは](https://www.nic.ad.jp/ja/basics/terms/anycast-address.html)
:::

これまではCloudFrontでは、以下の通り静的なIPはサポートされていませんでした。

https://repost.aws/ja/knowledge-center/cloudfront-distribution-static-ip

>CloudFront は、ディストリビューションに対する静的 IP アドレスの割り当てをサポートしていません。

#### 確認してみよう
CloudFrontの新しいAnycast静的IPの解説やAWSコンソールでの説明はこちらに記載がありました。

https://aws.amazon.com/jp/blogs/networking-and-content-delivery/zero-rating-and-ip-address-management-made-easy-cloudfronts-new-anycast-static-ips-explained/

##### 構成する手順
CloudFrontディストリビューションでAnycast IPを有効にするには:
1.価格クラスは全てのエッジの場所を使用 IPv6:無効
2.SNIを使用してHTTPSリクエストにサービスを提供するようにCloudFrontを構成
3.Anycast IPリストを作成
4.リストが作成されたら、CloudFrontディストリビューションに関連付けます。

#### コンソールを見てみる
Static IPsのメニューを発見！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/9597ae18-732b-a832-ec69-45193483c663.png)

#### 利用条件
>Request
Contact support engineering  with your workload information:
Request bytes per second
Requests per second
The support engineer will review your request and enable you to create an Anycast static IP list.

サポートエンジニアにワークロード情報を提供してリクエストが必要なようですね。

デフォルトではクォータ値が0のため、作成は出来ません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/31638741-44bd-c8da-3ffa-f3e80958d4e1.png)

一応試しましたがNG
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/b42e3da5-5ca2-636c-ce8b-6342ea7c994a.png)

#### まとめ
CloudFrontのAnycast静的IPアドレス機能は、ファイアウォールや、ネットワークの柔軟な管理が求められるシナリオで便利そうですね。
ただし、事前に申請する必要があるため、計画的に利用の検討が必要そうです。
【JavaScript】文字列がBase64か検証する方法

以下のようにすると文字列がBase64か検証できます。

```javascript
const base64Regex =
  /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/
  
console.log(base64Regex.test("SomeStringObviouslyNotBase64Encoded...")) // false
console.log(base64Regex.test("U29tZVN0cmluZ09idmlvdXNseU5vdEJhc2U2NEVuY29kZWQ=")) // true
console.log(base64Regex.test("SGVsbG8gV29ybGQ=")) // true
console.log(base64Regex.test("InvalidBase64String!@#")) // false
```
【Rails】Relation#delete_allとCollectionProxy#delete_allの違い

## はじめに

Ruby on Railsで複数のレコードを削除する際に使用されるメソッドとして`Relation#delete_all`と`CollectionProxy#delete_all`があります。

この記事では両者の違いをまとめます。

## `Relation#delete_all`と`CollectionProxy#delete_all`の違い

まずは両者の基本的な違いを確認します。

### `Relation#delete_all`

`Relation#delete_all`はActive Recordの`Relation`オブジェクトに対して使用されるメソッドです。

指定した条件に合致するレコードを一括で削除します。

SQLのDELETE文を直接発行するため非常に高速に動作しますが、削除時にモデルのコールバックやバリデーションは実行されません。

#### 使用例

```ruby
# ステータスが'inactive'のユーザーを一括削除
User.where(status: 'inactive').delete_all
```

### `CollectionProxy#delete_all`

一方、`CollectionProxy#delete_all`はActive Recordの関連付けを通じてアクセスされるオブジェクトに対して使うメソッドです。

`has_one`や`has_many`などの関連づけられたコレクションに対して一括削除を行います。

#### 使用例

```ruby
# 投稿に紐づくコメントを削除
post = Post.first
post.comments.delete_all  # postsテーブルとcommentsテーブルの関連付けを通して削除
```

## 引数の取り扱いの違い

`Relation#delete_all`と`CollectionProxy#delete_all`は引数の扱いが異なります。

実際のRailsのコードで確認します。

### `Relation#delete_all`

`Relation#delete_all`は引数を受け取りません。

#### 参考：`Relation#delete_all`の定義

```ruby:activerecord/lib/active_record/relation.rb
def delete_all
  return 0 if @none

  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
    value = @values[method]
    method == :distinct ? value : value&.any?
  end
  if invalid_methods.any?
    raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
  end

  model.with_connection do |c|
    arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
    arel.source.left = table

    group_values_arel_columns = arel_columns(group_values.uniq)
    having_clause_ast = having_clause.ast unless having_clause.empty?
    key = if model.composite_primary_key?
      primary_key.map { |pk| table[pk] }
    else
      table[primary_key]
    end
    stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)

    c.delete(stmt, "#{model} Delete All").tap { reset }
  end
end
```

https://github.com/rails/rails/blob/main/activerecord/lib/active_record/relation.rb#L1011

### `CollectionProxy#delete_all`

`CollectionProxy#delete_all`は内部的に引数`dependent`オプションを受け取る実装となっています。

ただしユーザーが直接引数を渡すことは想定されておらず、あくまでもActive Record内部の処理用です。

関連付けを定義する際、以下のように`dependent`オプションを付与するかと思います。

```ruby:app/models/user.rb
class User < ApplicationRecord
  has_many :posts, dependent: :destroy  # dependentオプションを設定
end
```

ここで設定した内容に応じて、`dependent`オプションに引数が渡され、`CollectionProxy#delete_all`の挙動が変わるのです。

#### 参考：`CollectionProxy#delete_all`の定義

```ruby:activerecord/lib/active_record/relation.rb
def delete_all(dependent = nil)
  @association.delete_all(dependent).tap { reset_scope }
end
```

https://github.com/rails/rails/blob/main/activerecord/lib/active_record/associations/collection_proxy.rb#L474

## おわりに

- `Relation#delete_all`: 引数を受け取らない
- `CollectionProxy#delete_all`: Active Recordの内部で引数を受け取る

恥ずかしながら両者の違いを意識せず同じ`delete_all`メソッドとして使っていました。

今後はこういった、Railsの内部挙動にも注意を払っていきたいです。

### 参考

https://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-delete_all

https://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-delete_all
[備忘録][Cording][基礎知識]文字種の基礎知識

# [備忘録][Cording][基礎知識]文字種の基礎知識
## 文字種一覧
| 種類               | 説明                     | 例         | Unicode範囲    | バイト数(UTF-8/UTF-16) |
| ------------------ | ------------------------ | ---------- | -------------- | ---------------------- |
| ASCII              | 半角英数字・記号         | A, 1, @    | U+0000-007F    | 1/2                    |
| 半角カタカナ       | JIS X 0201カタカナ       | ｱ, ｶ, ﾝ    | U+FF61-FF9F    | 3/2                    |
| 基本ラテン文字拡張 | アクセント付きラテン文字 | é, ñ, ü    | U+0080-00FF    | 2/2                    |
| ひらがな           | 日本語ひらがな           | あ, い, う | U+3040-309F    | 3/2                    |
| カタカナ           | 日本語カタカナ           | ア, イ, ウ | U+30A0-30FF    | 3/2                    |
| 漢字               | [CJK統合漢字](https://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/cjku_klist.html)              | 日, 本, 語 | U+4E00-9FFF    | 3/2                    |
| 結合文字           | アクセント記号など       | ◌́, ◌̈, ◌̃    | U+0300-036F    | 2/2                    |
| 異体字セレクタ     | 漢字の異体字指定         | 辻󠄀, 神󠄁     | U+E0100-E01EF  | 3+4/2+2                |
| 絵文字             | 絵文字基本セット         | 😀, 🌟, 🎈    | U+1F300-1F9FF  | 4/4                    |
| 絵文字修飾子       | 肌の色など               | 👶🏻, 👶🏽, 👶🏿    | U+1F3FB-1F3FF  | 4+4/4+2                |
| サロゲートペア     | 追加文字面の文字         | 𠮟, 𩸽       | U+10000-10FFFF | 4/4                    |
| ZWJを使った絵文字                | ゼロ幅接合子 + 複数のコードポイントで構成             | 👨‍👩‍👦, 👨‍💻       | U+200D         | 3/2                    |


## 曲者文字一覧
| 文字 | コードポイント | 補足                                                       |
| ---- | -------------- | ---------------------------------------------------------- |
| é̳̲̥̤    | 5              | 結合文字を含む文字(ラテン文字 + 複数の結合文字)            |
| 한   | 1              | ハングル音節文字                                           |
| क्षि   | 4              | ヒンディー語などで使われる文字(複数の文字要素の組み合わせ) |
| 🏴󠁧󠁢󠁥󠁮󠁧󠁿    | 5              | 国旗絵文字                                                 |
| 👨‍👩‍👧‍👦    | 7              | ZWJ（Zero Width Joiner）と複数のコードポイントで構成する文字列                   |

## 曲者文字によって文字数カウントが狂わされないようにするためには
### ① 変な文字を許容しない
- 扱うデータの性質によっては半角英数字のみ、数字のみ、など入力できる文字種が制限されるため、そういう情報はそもそも入力させないのが吉(正規表現で簡単にできる)。
- さらに広くしてひらがな、カタカナ、漢字を許容するのであれば、正規表現またはUnicodeによって制御ができる

### ② 書記素でカウントする
- javascriptであれば `Intl.Segmenter` を使ってカウントできる(参考: [String: length](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/length))
  - ※比較的最新のブラウザしか対応していないので注意が必要

## 参考資料
https://qiita.com/suin/items/3da4fb016728c024eaca#intlsegmenter
javascript 　基礎

『学習備忘録』

typeof:　型を調べるもの
number: 数値を表すﾃﾞｰﾀ型（整数、小数）
```.js
if (typeof hoge !== 'number')
// hogeがnumber型ではない時にtrueを返す
// numberとすると変数という認識になってしまうため''で囲う

if (!Number.isInteger(hoge))
// hogeが整数ではない時にtrueを返す　内部ではnumber型かどうか、整数かどうかを確認している

if (typeof hoge !== 'number' || !Number.isInteger(hoge) || hoge < 1 || hoge > 7) {
  return null;
}
// hogeというものが上記のどこかでtrueになるとnullを返す
```
ubuntu20.04Virtual Host設定及びCertbotで無料で SSL 証明書を発行

Apacheのインストール
```
apt update
apt install apache2

まずはVirtual Host設定

cd /var/www/
mkdir example
cd /etc/apache2/sites-available
vi www.example.com.conf
下記のように編集保存。
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName www.example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example
</VirtualHost>

設定ファイルwww.example.com.confを下記コマンドで有効にします。
a2ensite www.example.com.conf
service apache2 restart
```
Certbotで無料で SSL
```
apt-get install certbot python3-certbot-apache
certbot --apache -d www.example.com
```
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2を選択
```
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
```
上記で、２を選択すると、自動でhttpsへリダイレクトされます。１の場合はconfファイルはそのままで、リダイレクトされます。
cd /etc/apache2/sites-available
vi www.example.com-le-ssl.conf
下記のように生成されます。
```
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerAdmin webmaster@localhost
    ServerName www.example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/linevetssmessenger
    
SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
```
更に最初に作成したwww.example.com.confに以下のような変更が生成されます。

vi www.example.com-le-ssl.conf
```
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName www.example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/linevetssmessenger
RewriteEngine on
RewriteCond %{SERVER_NAME} =www.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
```
systemctl reload apache2 すると自動的にhttpsへリダイレクトされます。
最新の certbot には自動更新の機能がありますので、特別何かを設定する必要はありません。正しく動作しているかsystemctl status certbot.timerで確認してみましょう。
```
systemctl status certbot.timer
● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Tue 2024-11-19 21:34:29 JST; 1 day 22h ago
    Trigger: Fri 2024-11-22 07:30:13 JST; 11h left
   Triggers: ● certbot.service

11月 19 21:34:29 v133-18-209-152 systemd[1]: Started Run certbot twice daily.
```


参考サイト:https://tks2.co.jp/2021/10/07/ubuntu-certbot-2021/
linuxの「btmpコマンド」とは？

Linuxにおける「`btmp`」とは、システムの不正なログイン試行（失敗したログイン試行）を記録するためのバイナリ形式のログファイルです。このログは、セキュリティの監視や不正アクセスの検知に役立ちます。

### 特徴

- **ファイルパス**
  通常、`/var/log/btmp` に配置されています。
- **内容**
  ログインが失敗したユーザー名、IPアドレス、試行された時刻などの情報が含まれています。
- **形式**
  バイナリ形式で保存されているため、直接テキストエディタで確認することはできません。ログの内容を見るためには専用のコマンド（`lastb`）を使用します。

### 関連コマンド

- `lastb` **コマンド**
  `btmp` の内容を読みやすい形式で表示します。
  ```
  lastb
  ```
  ‌
  出力例:
  ```
  root ssh:notty 192.168.1.10 Fri Nov 10 10:22:15 2023 - Fri Nov 10 10:22:15 2023
  ```
  ‌
- `btmp` **ファイルのクリア**
  ファイルサイズが大きくなりすぎた場合などは、内容を削除することで管理できます。ただし、必要に応じてバックアップを取っておくことを推奨します。
  ```
  > /var/log/btmp
  ```

### 注意点

1. **ログローテーション**
   一部のLinuxディストリビューションでは、`btmp` ファイルも定期的にローテーションされます（通常は `logrotate` によって管理される）。
2. **権限とセキュリティ**
   `btmp` ファイルは敏感なセキュリティ情報を含む可能性があるため、アクセス権限は厳格に制御されています。通常、root ユーザーのみがアクセス可能です。
3. **無効化する場合**
   必要がない場合やログを記録したくない場合は、設定を変更して `btmp` の記録を無効化できます。ただし、セキュリティ上の理由から推奨されません。

### btmp が存在しない場合

システムによっては、`btmp` ファイルがデフォルトでは作成されていないことがあります。その場合、次のようにして手動で作成できます。

```
sudo touch /var/log/btmp sudo chmod 600 /var/log/btmp
```

これにより、不正ログイン試行が記録されるようになります。
1.Appiumの環境構築～テスト実行


**1.Appiumの環境構築～テスト実行**

モバイルデバイスのテスト自動化ツールであるAppiumについて、環境構築手順、スクリプト作成、テスト実行手順等の情報が少ないため記事にまとめます。

公式のドキュメントはこちら
環境構築等の手順がクイックスタートとしてまとまっているので一読推奨

https://appium.io/docs/en/2.12/quickstart/

<br>
<br>

・目次
1.Appiumとは
2.環境構築
　2.1.Windows版 android環境
　2.2.Windows版 ios環境
　2.3.Mac版 android環境
　2.4.Mac版 ios環境
 
3.スクリプト作成
4.テスト実行
5.環境の更新情報

<br>
<br>



1.Appiumとは
---

Appiumとは、モバイルデバイスを自動的に動作させ、テストを自動化することができるオープンソースのテスト自動化ツールであり、Webブラウザを自動的に動かすSeleniumのアプリケーション版



<br>
<br>
<br>

2.環境構築
---

<br>

https://qiita.com/BubbleBubble/items/cf661a597f0957ab8ef2

<br>
<br>
<br>

3.スクリプト作成
---

<br>

https://qiita.com/BubbleBubble/items/8b1b78da5f9e36c44290

<br>
<br>
<br>

4.テスト実行
---

https://qiita.com/BubbleBubble/items/d21910c1e72b5d1153a9

<br>
<br>
<br>


5.環境の更新情報
---

https://qiita.com/BubbleBubble/items/6e43a7592cc9baef69ad

<br>
<br>
<br>

以上！
プロパティ一気に追記したいときの自分用シェルメモ

```
#!/bin/bash

# プロパティファイルが格納されているディレクトリ
TARGET_DIR="./config"

# 処理対象のファイルを探す
find "$TARGET_DIR" -type f -name "application.properties" | while read -r FILE; do
  # "parameter.example" が含まれていない場合はスキップ
  if ! grep -q "parameter.example" "$FILE"; then
    echo "Skipping $FILE (no 'parameter.example' found)"
    continue
  fi

  # 1. ファイル末尾に以下を追加
  echo -e "\n## hoge\nparameter=11" >> "$FILE"
  echo "Appended base parameters to $FILE"

  # 2. "parameter.example.****=someparameter_1abc" の行を探す
  grep -E "^parameter\.example\.[a-zA-Z]+=" "$FILE" | while read -r LINE; do
    # "parameter.example.bk.****=someparameter_2abc" を追加
    NEW_LINE=$(echo "$LINE" | sed 's/parameter\.example\./parameter.example.bk./')
    echo "$NEW_LINE" >> "$FILE"
    echo "Added backup line to $FILE: $NEW_LINE"
  done
done

echo "Processing complete."

```


```
#!/bin/bash

# プロジェクトディレクトリを探索する親ディレクトリを指定
BASE_DIR="."

# 各プロジェクトディレクトリをループ
for PROJECT_DIR in "$BASE_DIR"/*; do
    # ディレクトリでなければスキップ
    if [ ! -d "$PROJECT_DIR" ]; then
        continue
    fi

    # env/test ディレクトリが存在するか確認
    TEST_DIR="$PROJECT_DIR/env/test"
    if [ -d "$TEST_DIR" ]; then
        echo "Processing $PROJECT_DIR"

        # env/prd ディレクトリを作成（既に存在する場合はスキップ）
        PRD_DIR="$PROJECT_DIR/env/prd"
        mkdir -p "$PRD_DIR"

        # env/test の中身を env/prd にコピー
        cp -r "$TEST_DIR/"* "$PRD_DIR"

        echo "Copied contents from $TEST_DIR to $PRD_DIR"
    else
        echo "Skipping $PROJECT_DIR (env/test not found)"
    fi
done

pause

echo "CopyEnd"

# 置換対象の文字列と置換後の文字列を指定
declare -A replacements=(
    ["hogeTest"]="hogePrd"
    ["exampleKey"]="exampleValue"  # 必要に応じて追加
)

# 各プロジェクトディレクトリをループ
for PROJECT_DIR in "$BASE_DIR"/*; do
    # ディレクトリでなければスキップ
    if [ ! -d "$PROJECT_DIR" ]; then
        continue
    fi

    # env/prd/hoge.json ファイルのパスを確認
    HOGE_JSON="$PROJECT_DIR/env/prd/hoge.json"
    if [ -f "$HOGE_JSON" ]; then
        echo "Processing $HOGE_JSON"

        # 置換を実行
        for search in "${!replacements[@]}"; do
            replace=${replacements[$search]}
            echo "Replacing '$search' with '$replace' in $HOGE_JSON"
            sed -i "s/$search/$replace/g" "$HOGE_JSON"
        done
    else
        echo "Skipping $PROJECT_DIR (env/prd/hoge.json not found)"
    fi
done

echo "Script execution completed."


```
仮想インターフェースを Hyper-V で作成する

　この記事ではお使いの Windows コンピューターに Hyper-V を用いた仮想インターフェースの作成方法を解説します。

::: note alert
この記事はお使いのコンピューターの **Hyper-V が有効になっている** ことが前提です。Windows Home エディションの方は **デフォルトで Hyper-V が使用できません！** Hyper-V が使用できない場合は [**Windows 11 Home で Hyper-V を有効にする方法**](https://qiita.com/GAI-313/items/a3ac77676a513d74e2a6) を参考に Hyper-V を有効にしてください。
:::

　仮想インターフェースを作ることで WSL などの仮想環境でホストと同じ IP アドレスまたは追加のデバイスとして外部ネットワークに接続することができるようになります。

# 仮想インターフェースを作成する
::: note warn
　仮想インターフェースの作成対象となるのは **有線LAN（Ethernet）** です。有線LAN を搭載していないコンピュータを使用している場合はハブなどを用いて有線LAN を使える環境にしてください。
:::
　まず、スタートメニューで ***「Hyper-V」*** と検索してください。すると候補で **「Hyper-V マネージャー」** がでます。こちらのアプリを開いてください。
<img src="https://funakamome.com/i/86954b47f989d32961db995e7b14baba.png" />

　Hyper-V マネージャーの操作パネルにある ***「仮想スイッチマネージャー」*** をクリックしてください。
<img src="https://i.imgur.com/PXRp8UV.jpeg" />

::: note
### 上の画像の項目が表示されない場合
　上の画像のように ***「仮想スイッチマネージャー」*** などの項目が表示されない場合、以下のような画面になっているかと思われます。この場合はこのウィドウの左側の **Hyper-V マネージャー** の項目の下にあるお使いのコンピューターの名前の項目をクリックしてください。
<img src='https://i.imgur.com/fSix43R.jpeg'/>
:::

　はじめは以下のようなウィンドウが表示されます。下の画像のように、最初に *「新しい仮想ネットワークスイッチ」* をクリックしてウィンドウ右側に表示される「外部、内部、プライベート」のうち **「外部」** を選択してください。最後に *「仮想スイッチの作成」* をクリックして次の作業へ移ります。
<img src='https://i.imgur.com/Mu4Xg3R.jpeg'/>

　すると以下のようなメニューがー表示されます。ここでは仮想インターフェースの構成を設定します。
<img src='https://i.imgur.com/w6dPoQQ.jpeg'/>
 
　はじめに仮想スイッチプロパティの名前の項目にわかりやすいプロパティ名を設定してください。今回仮想の有線LANインターフェース（Ethernet）を作成するので、**`vm_ethernet`** という名前にしました。特に理由がない方はこの記事で設定したインターフェース名にするといいでしょう。
<img src="https://i.imgur.com/4sJJqG9.jpeg" />

　接続の種類グループの仮想スイッチの種類を **「外部ネットワーク」** にしてください。すると、インターフェースを選択する項目が現れるのでこちらを **Wi-Fi** という名前がついていないインターフェース名を選択してください。
<img src="https://i.imgur.com/ZOhr4nL.jpeg" />

　設定が完了したら、ウィンドウ右下の「適応」をクリックしてください。するとこのような警告が表示されますが、「はい」をクリックして設定を完了してください。「変更を適応しています」というポップアップが消えたら「OK」をクリックして仮想スイッチマネージャーを閉じます。
<img width=5%/><img width=45% src="https://i.imgur.com/6KxAo9G.jpeg" /><img width=5%/><img width=45% src="https://i.imgur.com/Q2kAlop.jpeg" />

---

これでお使いの Windows に Hyper-V による仮想インターフェースが作成できました！
【Postgresql】 GroupByがエラーになるので、使い方を整理してみた

# ひとりごと
DB初心者がpostgresqlを学んでいこうと思い、メモ代わりに投稿してみます。

# はじめに
DBのお勉強をしていてgroup byを使ってみよう。と思ったら、こんなエラーが出てしまった。
> ERROR:  column "eiga.売上合計" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: select 売上合計 as A ,映画タイトル from eiga group by 映画タ...

このエラーについて原因を考えてみようと思う。


# 対象テーブル
| 売上id | 売上合計 | 映画タイトル     | 売上日       |
|:------:|:--------:|:---------------:|:------------:|
|   1    |   12000  | 映画タイトル1   | 2024-01-01   |
|   2    |   15000  | 映画タイトル2   | 2024-01-01   |
|   3    |   11000  | 映画タイトル3   | 2024-01-02   |
|   4    |   13000  | 映画タイトル1   | 2024-01-02   |
|   5    |   16000  | 映画タイトル5   | 2024-01-03   |
|   6    |   17000  | 映画タイトル6   | 2024-01-03   |
|   7    |   14000  | 映画タイトル7   | 2024-01-04   |
|   8    |   12500  | 映画タイトル8   | 2024-01-04   |
|   9    |   13500  | 映画タイトル9   | 2024-01-05   |
|   10   |   14500  | 映画タイトル10  | 2024-01-05   |


# なぜエラーになったのか
今回の目標は映画タイトルごとの売上合計を求めることである。
そのために、私は以下SQLを投げた。そしてその結果、エラー（再掲）が出てしまった

```ruby:qiita.rb
select 売上合計,映画タイトル from eiga group by 映画タイトル
```

> ERROR:  column "eiga.売上合計" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: select 売上合計 as A ,映画タイトル from eiga group by 映画タ...

いきなり結論だが、
**このSQLだとレコードを一意に特定できないので、エラーになったのだと思う。**


このSQLは映画タイトルでグルーピング（※）しているが、
映画タイトルでグルーピングすると、売上合計は12,000と13,000のどっちをselectしてくればいいかを判断できない。

| 売上id | 売上合計 | 映画タイトル     | 売上日       |
|:------:|:--------:|:---------------:|:------------:|
|   1    |   12000  | 映画タイトル1   | 2024-01-01   |
|   4    |   13000  | 映画タイトル1   | 2024-01-02   |

一方で、
```ruby:qiita.rb
select sum(売上合計),映画タイトル from eiga group by 映画タイトル
```
とすると売上合計は合算されるので、エラーにならないのである。

# ひとりごと
以上です。ご指摘等あれば、いただければと:point_up:
【オンライン】Linux標準教科書の開発リーダーに聞く、アウトプットの重要性（11/21）に参加してきた！

# はじめに
<!-- 発端や概要を記載 -->
本記事ではLiON様主催オンラインイベントの感想記事になります。
個人的に勉強、タメになったことをつらつらと書かせていただきます。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. イベントの趣旨
2. 学びになったこと
3. まとめ
4. 参考記事

<!-- 各チャプター -->
# イベントの趣旨
今回のイベントでは、Linux標準教科書の開発リーダーである宮原　徹氏から「アウトプットの重要性」をメインテーマとしたトークセッションが行われました。

講演を聴くだけではなく、参加者全員の自己紹介や、交流タイムも組み合わせた全員参加型イベントとなっております。

# 学びになったこと

### アウトプットの入り口
アウトプットの入り口として、
「手順をメモや手順書に書き起こす」といった例が挙がりました。

私は業務でよく
「インプットする→インプットした内容を実施する→報告する」
といった流れを実施しますが、報告が伝わらないことが多々あります…
「→」である、プロセスをメモや手順書に書き起こすのが大事だと学びました。

また、「アウトプット」と聞くと、どうしても「他人に共有する（パブリック）」という固定概念で覆われいましたが、
- ソースコードを書く
- メモを書く
- ToDoリストを書く

といったプライベートでも実施できることにも気づきました。

### アウトプットのステップアップ

「手順をメモや手順書に書き起こす」が慣れたら、
1. ブログに手順を書き起こす
2. イベントの場で発表者として手順を共有する
3. 大勢の人たちへ手順を広めるために教科書を作る

といったステップアップの話も挙がりました。

勉強でもそうですが、ハードルが高すぎると挫折してしまいますよね。
ステップを設けることで、計画的に行動する意識をする必要性があると思いました。

### ノウハウを共有する大事さ
自分の書いたメモをローカルに保存するだけでなく、外部に公開することでノウハウを共有するのも立派なアウトプットだと話題が上がりました。

書き手はメモを外部に公開することで、「他人に見られる」といった意識を持つことでメモの品質が上がりますし、受け手はメモを見ることで容易にインプットできるといった相乗効果が生まれるのもアウトプットの良さだと気づきました。

# まとめ
今回のイベントを通して、「アウトプットの重要性」について学びました。
アウトプットする第一歩を踏み出したものの、どう能力を高めればよいか迷っていた自分にとって良い機会でした！

またノシ

# 参考記事
- [LinuC Open Network](https://linuc.community/)
- [【オンライン】Linux標準教科書の開発リーダーに聞く、アウトプットの重要性](https://lion.connpass.com/event/336339/?utm_campaign=event_reminder&utm_source=notifications&utm_medium=email&utm_content=title_link)
bolt.newをローカル環境で動かす

# bolt.newをローカル環境で動かす完全ガイド

bolt.newは、テキストのみでフルスタックアプリケーションを開発できる革新的なAIツールです。この記事では、MacでのローカルセットアップからAnthropicのAPI設定まで、詳しく解説します。

## 前提条件

以下のソフトウェアが必要です。

- Node.js (v20.15.1以上)
- pnpm (v9.4.0以上)
- Git

また、今回はMacOSでのセットアップ前提としています。

ターミナルを立ち上げて、以下の手順を実行してください。

## Node.jsのインストール

### Homebrewを使用したインストール

```bash
brew install node

```

インストールが完了したら、以下のコマンドでバージョンを確認します：

```bash
node -v

```

バージョンが表示されれば、インストール成功です。

## pnpmのインストール

Node.jsがインストールされていることを確認してから、以下の手順で進めます：

### Homebrewを使用したインストール方法

```bash
brew install pnpm

```

インストール後、以下のコマンドでバージョンを確認します：

```bash
pnpm -v

```

正しいバージョン番号が表示されれば、インストール完了です。

## Gitのインストール

### Homebrewを使用したインストール

```bash
brew install git

```

インストール後、以下のコマンドで確認します：

```bash
git --version

```

### Gitの初期設定

インストール後、以下の設定を行います：

```bash
git config --global user.name "あなたの名前"
git config --global user.email "あなたのメールアドレス"

```

この設定により、Gitでの作業履歴に名前とメールアドレスが記録されます。

## インストール確認

すべてのインストールが完了したら、以下のコマンドで各ツールのバージョンを確認します：

```bash
node -v    # Node.jsのバージョン確認
pnpm -v    # pnpmのバージョン確認
git --version    # Gitのバージョン確認

```

それぞれのコマンドが正常に動作し、バージョン番号が表示されれば、すべてのセットアップは完了です。


## セットアップ手順

ターミナルを立ち上げて、以下の手順でセットアップを行う。

### 1. リポジトリのクローン
bolt.newのリポジトリ
https://github.com/stackblitz/bolt.new

```bash
git clone <https://github.com/coleam00/bolt.new-any-llm.git>
cd bolt.new-any-llm

```

### 2. 依存関係のインストール

```bash
pnpm install

```

### 3. AnthropicのAPIキー取得

Anthropic公式サイトから、APIのシークレットキーを取得する。

公式サイト：https://console.anthropic.com/login?returnTo=/?

※今回は、説明を省きます。

### 4. 環境設定ファイルの作成

```bash
touch .env.local

```

.env.localファイルに以下の内容を追加：

```
ANTHROPIC_API_KEY=<取得したAPIキーを入力>
VITE_LOG_LEVEL=debug

```

### 5. アプリケーションのビルドと起動

```bash
pnpm run build
pnpm run start

```

ビルドが完了すると、「built in X.XXs」というメッセージが表示されます[1]。

## 動作確認

ブラウザで`http://localhost:8788`にアクセスし、bolt.newの画面が表示されることを確認します。

## トラブルシューティング

- ビルドエラーが発生した場合は、依存関係が正しくインストールされているか確認してください
- APIキーが認識されない場合は、.env.localファイルの内容を再確認してください
- Gitのエラーが出た場合は、Gitがインストールされているか確認してください

## 注意事項

- AnthropicのAPIは商用利用規約の対象となっています
- APIキーは一度しか表示されないので、必ず安全な場所に保存してください[4]
- 環境設定ファイルを変更した場合は、必ずビルドを再実行する必要があります

※この記事は、一部AIを使用して執筆しております。
Azure App Service で LogFiles のダウンロードの仕方

# 背景

App Service で 異常動作の調査する際にログを詳細に見たかった為の備忘録

LogFile は UTC で日付単位に保存されるっぽいので注意

# LogFiles のダウンロードの仕方

## 単純に最新だけ

- kudu で、<code>Download as zip</code> を選択してダウンロード
   ![2024-11-19_12h11_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/c7aa54e9-1ded-259d-3153-82601563bc78.png)

## 過去ログも含めて

この方法なら、ログ以外も全部ダウンロードできるので便利 :p 

1. kudu の bash にて、圧縮する。
   例） 
   > zip -r logfiles.zip /home/LogFiles
1. kudu で、<code>Files</code> から、対象ファイルにアクセスしてダウンロード
   ![2024-11-19_13h13_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/59599d78-59a0-761c-0416-75c128f7c8d6.png)

1. <code>https://{app-name}.scm.azurewebsites.net/api/vfs/LogFiles.zip</code> にアクセスすれば、ダウンロード可能

## Log の種類

基本は、default_docker.log を見れば事足りる？

| ログファイル名             | 用途                                                          | 説明                                                                                  | 
|----------------------------|-----------------------------------------------------------|---------------------------------------------------------------------------------------|
| `docker.log`               | 全般的な Docker コンテナのログ                               | アプリケーションの実行中に発生した標準出力やエラー、コンテナのライフサイクルに関する情報                                |
| `default_docker.log`       | デフォルトのコンテナの動作に関する Docker ログ                | アプリケーションの標準的な実行状況や重要なイベント、エラーなどが記録                                                      | 
| `default_scm_docker.log`   | `default`スキーマ内の`scm`関連、デプロイメントプロセスやソースコードの管理      | デプロイメントプロセスやソースコードの管理、ビルドプロセスに関連する操作についての情報                                      |
| `easyauth_docker.log`      | EasyAuth 機能に関連する Docker ログ                           | EasyAuthは Azure App Service の認証・認可機能で、ユーザーの認証プロセスに関連する情報が記録                              | 
| `msi_docker.log`           | Managed Service Identity (MSI) に関連する Docker ログ        | MSIはアプリケーション内で使用するためのIDの管理や認証情報の処理に関するログ                                               | 

https://learn.microsoft.com/ja-jp/azure/container-instances/container-instances-get-logs

# あとがき

LogStream とか、Application Log とか、Deployment Log とか・・
色々あって、最初は何が何だか・・

ファイルアップロードって、FTP だと面倒なんだけど、なんかいい方法はないものか・・
JDBCサンプルコード

ローカルのMySqlへのJDBC接続のコードです。
codeのJavaプロジェクトにmysqlのjdbcドライバ(mysql-connector-j-9.1.0.jar）を追加しておく。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.SQLException;

Public class App{
  public static void main(String[] args){
    db();
  }
  
  private static void db(){
    String URL = "jdbc:mysql://localhost:3306/";
    String dbDriver = "com.mysql.cj.jdbc.Driver";
    String dbName = "test";
    String dbUser = "user";
    String dbPassword = "somePassword";

    try{
      Class.forName(dbDriver);
      Connection conn = DriverManager.getConnection(URL + dbName, dbUser, dbPassword);
      Statement stmt = conn.createStatement();
      stmt.executeUpdate("insert into someTable values (1,"test");
      
      stmt.close();
      conn.close();
    }catch(SQLException e){
      e.printStackTrace();
    }catch(ClassNotFoundException e2){
      e2.printStackTrace();
    }
    System.out.println("DB ok");
  }
}
AWS Certified AI Practitioner (AIF-C01) に合格した

# 1. はじめに
- 目的
    - 昨年(2023年度)、AWSの全ての資格を取得し、2024 All Certifications Engineersになった。
    - 今年も全資格取得維持のため、新資格のAWS Certified AI Practitionerにチャレンジする。
- 受験前のレベル感
    - 2年前にG検定やAWS Certified Machine learning - Specialty などの取得時、機械学習系の勉強をした。しかしほとんど忘れてしまっている。
    - SageMakerはほとんど使っていない。
    - BedrockはKnowledgeBaseでのRAG作成など、少しだけ業務で使っている。

# 2. 準備
## 先人の受験記
- [【一発合格】AWS Certified AI Practitionerの勉強方法について](https://benjamin.co.jp/blog/technologies/how-to-pass-aws-aif/)
    - 自分と同じようなレベル感だったため、書いてある通りにやろうと思った。
- [AWS Certified AI Practitioner (AIF-C01) 認定勉強](https://qiita.com/kikuziro/items/9591b5dd9425acf04144)
    - 書いてある内容は試験範囲の一部だが、具体例を挙げて分かりやすく解説があり参考になった。

## Skill Builder
- 「Official Question Set: AWS Certified AI Practitioner (AIF-C01) - Japanese」
    - 無料の20問の模擬試験があり、まずそれで実力確認をした。初見で90%正解だったため、「あんまり改めて勉強しなくても大丈夫かな？」という感じだった。

## 書籍
- [Amazon Bedrock 生成AIアプリ開発入門](https://www.amazon.co.jp/Amazon-Bedrock-%E7%94%9F%E6%88%90AI%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-AWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89-%E5%BE%A1%E7%94%B0/dp/4815626448)
    - 試験対策というわけではなく、元々勉強のために一通り読んでいて、ハンズオンも半分くらい実施していた。そのため、AI Practitionerに出る内容くらいの基礎知識が得られていた気がする。

## Udemy
- [[Practice Exams] AWS Certified AI Practitioner - AIF-C01](https://www.udemy.com/course/practice-exams-aws-certified-ai-practitioner/)
    - 心配だったので念のためUdemyの問題集も実施した。あまり時間をかけず、80%くらい正答できるようになった時点で終了とした。

# 3. 受験
- 結果：　768点 (700点以上で合格)　※あまり余裕がある点数ではなかった、、
- 分野別理解度：　一応満遍なくOKだった様子。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/903919c9-26ca-44cf-ce7d-6927fbab75a8.png)

- [「再受験無料キャンペーン」](https://pages.awscloud.com/GLOBAL-other-GC-traincert-aws-foundational-certification-2024-learn-jp.html?sc_channel=sm&sc_campaign=AWS_Certification&sc_publisher)の期間中だったため、若干気楽に受験できた。

# 4. 所感
- とりあえず、「AWS Certified AI Practitioner」 はあまり苦労なくできたので、次にもう一つの新資格の「AWS Certified Machine Learning - Assosiate」 に早めに取り組みたい。こちらはSageMakerなどを復習する必要がありそう、、
MacOS Sequoia 15.1.1 でTimeMachineがコケるようになった

Sequoia 15.1.1にアップデートしたら、TimeMachineが「〜へのバックアップを完了できませんでした」「一部のファイルが利用できなかったため、バックアップの作成が完了できませんでした。Macのロックを解除するとバックアップの作成が再開されます」というエラーを出しました。

どういうわけかわからないので、TimeMachineに使っていたディスクを初期化したりしてみたのですが同じエラーが出ます。

とりあえず、システム設定 → プライバシーとセキュリティ → フルディスクアクセス → TimeMachineがなかったら下の+から追加してオンにすると正常にバックアップできました。これが正しい解決法かどうかはわかりません。
gdb の実用的な使い方

「実践デバッグ技法 Norman Matloff、Peter Salzman 著、相川愛三訳 オライリージャパン」で gdb の実用的 ( 効率的 ) な使い方が紹介されていました。私の環境は、Windows11 に wsl を使って Ubuntu をインストールしています。テキストエディタは vim を使っています。

## 通常のデバッグの手順
通常は、次のような手順でソースコード ( ins.c ) をデバッグしていきます。insert_sort はコマンドライン引数で与えられた数値を昇順に並べ替えるプログラムです。
① ソースファイルを作成
 ```
 $ vim ins.c
 ``` 
② ソースファイルを -g を付けてコンパイル
```
$ gcc -g -o insert_sort ins.c
```
③ 12, 5 を引数に与えて実行してみる
```
$ insert_sort 12 5
```
④ エラー発生
⑤ gdb を起動
```
$ gdb insert_sort
(gdb) run 12 5
```
⑥ デバッグ作業でバグを推定して gdb 終了
```
(gdb) quit
```
⑦ ソースファイルを修正
```
$ vim ins.c
```
⑧ 再コンパイル
```
$ gcc -g -o insert_sort ins.c
```
⑨ 以下を実行して、動作 OK
```
insert_sort 12 5
5
12
```
もし ⑨ でエラーが発生すれば、⑤ からやり直します。

gdb はコマンドライン引数やブレークポイントを保持していますが、gdb を quit で終了するとそれらが失われます。デバッグで同じブレークポイントを設定したい場合は、毎回設定し直さなればなりません。gdb や vim は開きっぱなしで作業したほうが効率的です。

## シェルのジョブ管理
Linux のシェルにはジョブ管理機能があり、エディタやデバッガなどのジョブを切り替えて使うことができます。前項のデバッグ手順に、この機能を利用すると以下のようになります。
**fg ジョブid** は、フォアグラウンドでジョブを実行するコマンドです。 
参照: [ジョブを管理するコマンド](https://www.miraiserver.ne.jp/column/about_linux-job/)

① ソースファイルを作成後、Ctrl - z で vim を中断
 ```
 $ vim ins.c
 
 [1]+  Stopped                 vim ins.c
 ``` 
② ソースファイルを -g を付けてコンパイル
```
$ gcc -g -o insert_sort ins.c
```
③ 12, 5 を引数に与えて実行してみる
```
$ insert_sort 12 5
```
④ エラー発生
⑤ gdb を起動
```
$ gdb insert_sort
(gdb) run 12 5
```
⑥ デバッグ作業でバグを推定して Ctrl - z で gdb を中断
```
(gdb)
[2]+  Stopped                 gdb insert_sort
```
⑦ vim を再開して、ソースファイルを修正後、Ctrl - z で中断
```
$ fg 1
vim ins.c

[1]+  Stopped                 vim ins.c
```
⑧ 再コンパイル
```
$ gcc -g -o insert_sort ins.c
```
⑨ 以下を実行してみる
```
insert_sort 12 5
```
⑩ エラー発生
⑪ gdb を再開
```
$ fg 2
gdb insert_sort
run ( 以前の引数を利用するときは、引数を省略可能 )
   ...
`/home/ ～ /insert_sort' has changed; re-reading symbols.
   ...
```
`/home/ ～ /insert_sort' has changed; re-reading symbols.
は、プログラムが再コンパイルされたことを gdb が見つけ、プログラムを実行する前に、新しいバイナリ ( 実行コード ) とシンボルテーブルを自動的に読み込み直したことを示しています。

⑫ デバッグ作業でバグを推定して Ctrl - z で gdb を中断
```
(gdb)
[2]+  Stopped                 gdb insert_sort
```
⑬ vim を再開して、ソースファイルを修正後、Ctrl - z で中断
```
$ fg 1
vim ins.c

[1]+  Stopped                 vim ins.c
```
⑭ 再コンパイル・実行
```
$ gcc -g -o insert_sort ins.c
$ insert_sort 12 5
5
12
``` 
もし ⑭ でエラーが発生すれば ⑪ からやり直します。

## マルチウィンドウが使える場合
テキストエディタと、gdb を別々のウィンドウで起動しておき、第 3 のウィンドウで、プログラムのコンパイル、実行をおこなうようにします。

## Termdebug の利用

[VimからGDBを起動する方法](https://debimate.jp/2019/09/14/%E3%80%90vim8-1-x%E3%81%8B%E3%82%89%E6%A8%99%E6%BA%96%E6%A9%9F%E8%83%BD%E3%80%91vim%E3%81%8B%E3%82%89gdb%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%83%9E%E3%82%A6%E3%82%B9/) で紹介されていた、vim のプラグインで利用できる Termdebug もいいですね。

下記はデモ画面です。ソースファイルは until-anomaly.c、バイナリファイルは until-anomaly。「Hello world」 を 5 回印字するプログラムです。
左上はデバッガ ( gdb )、左下はプログラムの出力、右半分はエディタ ( vim ) の画面です。ブレークポイントや、プログラムの停止位置をソースコード上で確認できます。各領域を区切るバーをマウスでドラッグすると、領域のサイズを調整できます。
画面全体が崩れたときは、ウィンドウの全体のサイズをマウスで少し変更すると自動で戻るようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3549839/fbeb470e-8863-9db0-fa8e-b12dbd7007ff.png)
OpenGLは画像認識屋には手強すぎる

ZED SDKのサンプルを参照しながら、変更を加えていると思う。

OpenGLは画像認識屋には手強すぎる。

Open3Dのビューワーでなんとかなるならば、Open3Dを使うのがいいと思った。

理由：
## OpenGL
- OpenGLは、描画ライブラリとしての能力が高い。
- OpenGLは、クロスプラットフォームの描画ライブラリである。
- OpenGLは、描画ライブラリとしての汎用性が高い。

それらのことが、自由度の高さの分だけ、記述量が増えてしまうことにつながっているようです。
記述量が増えることは、その分だけ、理解していない人がバグを埋め込みやすい。
書いたコードが動作しないということにつながりやすいようです。

## Open3Dの場合
グラフィックスにしても利用される状況が限定的です。
そのため、記述量が少なくなります。


---
## コードの見本
## OpenGLのC++のコード例

https://github.com/stereolabs/zed-sdk/blob/master/object%20detection/image%20viewer/cpp/src/GLViewer.cpp

## Open3D のVisualizationの例

https://www.open3d.org/docs/release/tutorial/visualization/visualization.html


#### 追記
https://community.stereolabs.com/
で、opengl、glut、GLVIewer　で検索してみてほしい。
みんな、苦しんでいるのが分かる。
Biomeでpre-commit時に対象ファイルがないとエラーになるのを解消する

## この記事の概要

pre-commit時にBiomeのコマンドを走らせるとき、対象ファイルがないとエラーになり、コミットができません。

それを解消するための記事です。

## 状況

対象ファイルが無いというのは、例えば以下のような場合です

- チェック対象は.jsや.tsのファイル
- ライブラリのインストールだけをした
- 変更されたファイルはpackage.jsonとロックファイルだけ

このとき、デフォルトの挙動だとBiomeがエラーを吐き、コミットができません。

対象ファイルがないならないでコミットを実施したいです。

## 解消方法

`--no-errors-on-unmatched`フラグを使います。

例えばLefthookを使っていて、以下のようになっているのを

```yaml:lefthook.yml
pre-commit:
  commands:
    check:
      glob: "*.{js,ts,jsx,tsx}"
      run: npx @biomejs/biome check
```

このように変えるだけです。

```diff_yaml:lefthook.yml
  pre-commit:
    commands:
      check:
        glob: "*.{js,ts,jsx,tsx}"
-       run: npx @biomejs/biome check
+       run: npx @biomejs/biome check --no-errors-on-unmatched
```

もちろん、他のオプション（例えば`--staged`など）とも併用できます。

## 参考

https://biomejs.dev/recipes/git-hooks/#lefthook
なぜリスコフの置換原則を守らないといけないのか？

## はじめに
最近、設計の原則を知ってはいるものの、実際に活用できていない！と感じることがありました。
そこで、自分なりに「なぜその原則が重要なのか」を改めて考え直してみることにしました。
この記事では、TypeScriptを使ったコード例を交えながら説明しますが、普段お使いの言語に置き換えて読んでいただけるとありがたいです。

## リスコフの置換原則とは
リスコフの置換原則は、オブジェクト指向プログラミングにおける設計原則の一つです。
1994年にバーバラ・リスコフによって提唱され、継承の設計における重要な指針を示しています。
この原則では、基底クラスを継承した派生クラスのオブジェクトは、基底クラスのオブジェクトとして扱われても正しく動作するべきだとされています。
つまり、基底クラスを期待するコード内で派生クラスを使用しても、基底クラスとして一貫した振る舞いが保証される必要があります。

具体例として、Animalクラスを基底クラスとし、それを継承したLionクラスとDogクラスを考えてみましょう。
```TypeScript
class Animal {
  public bark() {
    console.log('吠える');
  }
}

class Tiger extends Animal {
  public bark() {
    console.log('がおー');
  }
}

class Dog extends Animal {
  public bark() {
    console.log('ワンワン！');
  }
}
```
Animalクラスを継承しているクラスであれば、どの派生クラスのインスタンスであってもbarkメソッドを実行することが期待されます。
```TypeScript
const tiger = new Tiger();
const dog = new Dog();

(tiger as Animal).bark(); // 「がおー」
(dog as Animal).bark(); // 「ワンワン！」
```
簡単ですが、これがリスコフの置換原則の基本的な考え方です。

## リスコフの置換原則に反している例
では、リスコフの置換原則に反しているクラス設計はどういう場合でしょうか。
ここではよく原則違反の例として引用される四角形（Rectangle）と正方形（Square）をクラス化した場合の例を使って説明します。
以下のように、RectangleクラスとSquareクラスを定義します。
```TypeScript
class Rectangle {
  constructor(private width: number, private height: number) {}

  public setWidth(width: number) {
    this.width = width;
  }

  public setHeight(height: number) {
    this.height = height;
  }

  public getArea() {
    return this.width * this.height;
  }
}

class Square extends Rectangle {
  constructor(length: number) {
    super(length, length);
  }

  public setSquare(length: number) {
    this.setWidth(length);
    this.setHeight(length);
  }
}
```
SquareクラスはRectangleクラスを継承しているため、setWidthとsetHeightメソッドを呼び出すことができます。
しかし、setWidthメソッドの引数を10、setHeightメソッドを20のように呼んでしまうと正方形ではなくなってしまいます。
```TypeScript
const square = new Square(10);
square.setWidth(10);
square.setHeight(20); // 正方形ではなくなる
```
想定していない状態が作れてしまうため、不具合に繋がる可能性が高い状態です。
このように、SquareメソッドはRectangleを継承しているにも関わらず、Squareメソッドのインターフェースが使えなくなってしまっています。
つまりSquareはRectangleとして振る舞うことができなくなってしまっており、リスコフの置換原則に反している状態です。

## リスコフの置換原則に反していた場合の弊害
ではなぜリスコフの置換原則に反してはいけないのでしょうか。
主に下記2つの理由が存在します。
1. コードの予測可能性が低くなる
1. 変更による影響範囲が読みづらくなる

### 1. コードの予測可能性が低くなる
リスコフの置換原則に反している場合、同じ基底クラスから継承している派生クラスであっても、基底クラスのコードが動作する場合と動作しない場合が発生します。
先ほどの例のように、SquareクラスはRectangleを継承していますが、setWidthやsetHeightの使用は想定通りに動作しません。
このような実装が存在していると、基底クラスのコードが期待通りに動作するかどうかを派生クラスごとに確認する必要が生じます。
その結果、次のような不要な分岐処理が増え、コードの見通しが悪くなります。
```TypeScript
const rectangle: Rectangle = new Square(10);

if (rectangle instanceof Square) {
  // 正方形のサイズ変更処理
} else {
  // その他の四角形のサイズ変更処理
}
```
### 2. 変更による影響範囲が読みづらくなる
基底クラスのインターフェースが派生クラスによって使えない場合があるということは、基底クラスと派生クラスが互いに影響し合っているということです。
これは基底クラスに何かしらの変更を行った場合に、派生クラスにどのような影響を与えるか考慮することが必要になるということになります。
本来は基底クラス内の影響だけ考えて変更すればいいはずが、派生クラスの影響調査を行うコストが発生してしまいます。
これは基底クラスで共通化することを避ける傾向にも繋がり、ますます見通しの悪いコードが増えていくことにも繋がります。

## まとめ
当たり前のように根付いてしまっている原則は「そういうもの」と捉えてしまいがちですが、
「なぜその原則ができたんだっけ？」「どんないいことがあるんだっけ？」というところまで考えるとまったく理解の解像度が違うなと感じました。
実際のコードを活用しながら理解を深めるのも大事ですね！