OmniAICreator/Qiita-1.07M huggingface dataset:
richeditor-android　使ってみた

# はじめに
https://github.com/wasabeef/richeditor-android?tab=readme-ov-file

↑こちらのライブラリを使ってみたところ、提供元に書かれていない内容で使えそうなものがあったので記事にしておこうかと思います。
# 準備


提供元の指示の通り　build.grableに以下を追加します。

```
dependencies {
  implementation 'jp.wasabeef:richeditor-android:2.0.0'
}
```

# 実装

```
<jp.wasabeef.richeditor.RichEditor
     android:id="@+id/rich_editor"
     android:layout_width="match_parent"
     android:layout_height="match_parent" />
```
layoutにRichEditorを実装し、Fragment側で使えるようにします。

このままの状態でも普通のEditTextのように扱えます。

---

```
binding.richEditor.setHtml(HtmlText);
```

このようにすることでテキストをセットでき、また、HTML形式のテキストをHTML.fromHtml()しなくても変換してくれます。


また、すでに入力された文字の中に返還後のものがあり、それをHTML形式に直したい場合は
```
binding.richEditor.getHtml();
```
とすることでHTML形式の文字を取り出すことができます。


# 終わりに
他にもたくさんの機能があったので、今後も使っていく中で便利なものがあったら追記、または、別記事で紹介していこうと思います。
[RDB] 正規化

# まとめ
**第1正規形**: 全ての属性が単一値である状態
**第2正規形**: 第1正規形をみたし、部分関数従属する属性が存在しない状態
**第3正規形**: 第2正規形をみたし、主キーからの推移的関数従属が存在しない状態

# 目次
- [第1正規形](#第1正規形)
- [第2正規形](#第2正規形)
- [第3正規形](#第3正規形)
- [例１](#例1)

# 第1正規形
全ての属性が単一値である状態
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/112389f1-a04b-17e7-6579-863e62cc04c2.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/66176c68-39ad-5209-28af-eab1b8ab8eb7.png)


# 第2正規形
第1正規形をみたし、部分関数従属する属性が存在しない状態

# 第3正規形
第2正規形をみたし、主キーからの推移的関数従属が存在しない状態

# 例1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/26736ad5-520d-4f64-e428-87e7ce4128f0.png)
これを図に直すと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/f78cb206-08e3-d06d-1781-81c99f17304b.png)

# 第1正規形
全ての項目が単一値（繰り返し項目がない）ので、第１正規形になっている。

# 第2正規形
主キーの一部（複合種キー）に部分関数従属する非キー属性を別の表に分解する操作。
つまり、①注文番号→注文日、　②注文番号→顧客番号、③（注文番号→）顧客番号→顧客名、⑥商品番号→商品名のリレーションは部分関数従属となり、下記3表に分離する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/a46caa34-7b81-0030-b5ac-c8299ab46453.png)

# 第3正規形
主キーに推移的関数従属している非キー属性を別の表に分解する操作。
つまり、③（注文番号→）顧客番号→顧客名は推移的関数従属となり、下記4表に分離する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/09a780a2-3665-d161-8af7-2e9b9b704325.png)


# 参考リンク
- [応用情報技術者令和4年春期問28 正規形と特徴の組合せ](https://www.ap-siken.com/kakomon/04_haru/q28.html)
- [応用情報技術者令和2年秋期問28 関係"注文明細"として ...](https://www.ap-siken.com/kakomon/02_aki/q28.html)
- [データベースの正規化](https://oss-db.jp/dojo/dojo_info_04)
FAXや郵送で特別ガチャ！アナログとデジタルを融合した新しい顧客コミュニケーション

## はじめに

近年、デジタル化が進む中で、FAXや郵送といったアナログチャネルの使用頻度が減少しています。しかし、これらのチャネルには独自の魅力があり、特に高齢者とのコミュニケーションには欠かせません。そこで、アナログチャネルを活性化させつつ、若い世代にも魅力的な仕組みとして、「FAXや郵送で特別ガチャが回せる」システムを提案します。

## システム概要

このシステムは、FAXや郵送でのやりとりを行うと、特別なデジタルガチャを回すことができる仕組みです。通常のオンラインガチャとは別に、アナログチャネルを利用した場合にのみアクセスできる特別ガチャを用意することで、FAXや郵送の利用を促進します。

## 主な特徴

1. アナログとデジタルの融合
2. 世代間コミュニケーションの促進
3. 顧客エンゲージメントの向上
4. アナログチャネルの新たな価値創出

## システム要件

### 1. FAXガチャシステム

- FAX送信時に特別なQRコードまたは数字コードを生成
- 受信したFAXをOCRで解析し、自動的にガチャ権を付与
- FAX送信者に対して、ガチャ参加用のURLをSMSまたはメールで通知

### 2. 郵送ガチャシステム

- 郵便局にて届いた郵送物（はがき、手紙など）にユニークなQRコードまたはスクラッチ式のコードが印刷されて相手に届けられる仕組み
- 届いた郵便物に印刷されたコードをウェブサイトで入力またはQRコードをスキャンすることでガチャに参加可能
- 郵便物の種類（年賀状、暑中見舞いなど）に応じて、季節限定のガチャを用意

### 3. ガチャシステム

- FAXや郵送専用の特別ガチャプールを用意
- 通常のオンラインガチャよりも当選確率を高く設定
- デジタルコンテンツ（画像、動画、音楽など）や実物の景品（商品券、限定グッズなど）を用意

### 4. ユーザー管理システム

- FAX番号や郵便番号と紐づけたユーザーアカウントを作成
- ガチャの利用履歴や当選履歴を管理
- ポイント制度を導入し、FAXや郵送の利用頻度に応じて特典を付与

### 5. 管理画面

- ガチャの設定（景品、確率、期間など）を行う管理機能
- FAXや郵送の利用状況を分析するダッシュボード
- ユーザーの利用傾向を可視化するレポート機能

## 実装手順

1. バックエンドシステムの構築
   - FAX受信サーバーの設置
   - OCR処理システムの実装
   - ガチャシステムのAPI開発

2. フロントエンドの開発
   - ガチャ画面のデザインと実装
   - ユーザーダッシュボードの作成

3. データベース設計
   - ユーザー情報、ガチャ履歴、景品管理のためのスキーマ設計

4. セキュリティ対策
   - 個人情報保護のための暗号化
   - なりすまし防止のための認証システム

5. 外部サービスとの連携
   - SMS配信サービスとの連携
   - 決済システムとの連携（有料ガチャの場合）

## 期待される効果

1. FAXや郵送の利用増加
2. 若年層のアナログチャネルへの興味喚起
3. 高齢者のデジタルサービス利用促進
4. 企業と顧客のコミュニケーション活性化
5. 新たなマーケティング手法の確立

## 課題と対策

1. プライバシー保護
   - 個人情報の取り扱いに関する同意取得
   - データの匿名化と暗号化の徹底

2. システムの安定性
   - 大量のFAXやアクセスに耐えうるインフラ整備
   - 定期的なバックアップと冗長化

3. 不正利用の防止
   - IP制限やアカウント認証の導入
   - 不自然な利用パターンの検知と対応

4. 法規制への対応
   - 景品表示法などの関連法規への準拠
   - 各国の賭博規制に関する調査と対応

## まとめ

FAXや郵送を活用した特別ガチャシステムは、アナログとデジタルの良さを融合した新しい顧客コミュニケーション手法です。この仕組みにより、世代を超えたコミュニケーションの活性化と、企業のマーケティング戦略の多様化が期待できます。技術的な課題はありますが、慎重に設計・実装することで、革新的なサービスとなる可能性を秘めていると思います。
【Mac】音量調節ショートカットを追加する【Raycast】

# はじめに

私のMacは **「F1、F2などのキーを標準的なファンクションキーとして使用」** 設定をしています。

https://support.apple.com/ja-jp/102439#:~:text=%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82-,%E3%82%AD%E3%83%BC%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AE%E5%8B%95%E4%BD%9C%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B,-%E3%80%8Cfn%E3%80%8D%E3%82%AD%E3%83%BC%E3%82%92

:::note
これにより、以下のメリットがあります。
- `F12`で開発者モードが開く（Chrome等）
- `F5`でデバッグモードが開く（VSCode等）
:::
:::note warn
一方で、以下のデメリットがあります。
- 音量調節のキーが増える（`F12` → `Fn + F12`の2キー）
- 明るさ調節も同様
:::
その中でも、**音量調節は厄介**で
「キーボード左下の`Fn`キー」と「キーボード右上の`F12`キー」は押しにくいです。

特に横になって使う時、**キーボードの右側・左側で完結させたい**と感じます。


# 1. Raycastのデフォルト機能

Raycastとは、Spotlightを大きく拡張したようなアプリです。

https://zenn.dev/ichigoooo/articles/5111e8a96a4c19

このRaycastの中に「Turn Volume Up」「Turn Volume Down」コマンドがありますので、設定します。

(検索から`Extentions`→さらに検索で`Volume`)

![スクリーンショット 2024-07-14 12.50.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/c8256301-eed3-6275-b85e-1c7433ff0ecf.png)

今回は、明るさ調整に合わせて「`Option + F1`」「`Option + F2`」を設定しました。

これでキーボード左側のショートカットは完成です。

# 2. Raycastにスクリプトを追加

キーボード右側のショートカットも設定します。

Raycastは複数のショートカットを設定できないので、新しくスクリプトを作成し、コマンドを追加します。

別記事にまとめました。

https://qiita.com/kohki_takatama/items/b3ce8926047a2c421558

# おわりに

- `（左）Option + F1` / `（左）Option + F2` 
- `（右）Option + F11` / `（右）Option + F12`

キーボードの左右に音量調整ショートカットを設定できました！

※US配列のため、人によっては他のショートカットになると思います
Pythonで始める機械学習入門～初学者でも安心のステップバイステップガイド～

# はじめに
機械学習という分野に興味を持ちながらも、「何から始めればいいのか？」と迷っている方も多いのではないでしょうか？
本記事では、Pythonを使いながら機械学習の初歩を学べるように解説していきます。
早速、最初の一歩を踏み出しましょう！

# 対象読者
- 機械学習に興味があるけれど、どこから手をつけて良いかわからない方
- プログラミングはしたことがあるが、機械学習は初めての方
- Pythonを使って新しいスキルを身につけたいと思っている方

# 目次
1. 機械学習とは何か
2. 機械学習に必要なPythonの基本
3. 最初の機械学習モデルを構築してみよう
4. データの前処理と特徴量選択の重要性
5. モデルの評価と改善
6. 実践編: 実データを使ってみよう

# 1. 機械学習とは何か
機械学習とは、データからパターンを学習し、その学習を基に予測や分類を行う技術のことです。AI（人工知能）の中核となる技術であり、近年はあらゆる分野で活用されています。

## 機械学習の基本について
機械学習は、大きく分けて次の3つのカテゴリに分類されます。
- **教師あり学習**: ラベル付きのデータ(例: 犬と猫の画像)を使ってモデルを訓練させる方法。
- **教師なし学習**: ラベルなしのデータ(例: 類似商品をクラスタリング)を分析し、規則性やパターンを発見する方法。
- **強化学習**: 行動と報酬(例: ゲームのプレイング)を学習し、最適な行動を探求する方法。

# 2. 機械学習に必要なPythonの基本
機械学習を進める前に、基本的なPythonの知識が必要です。以下に代表的なライブラリを紹介します。

## ライブラリの紹介
- **NumPy**: 数値計算を効率的に行うためのライブラリ
- **Pandas**: データ操作や分析のためのライブラリ
- **Matplotlib / Seaborn**: データの可視化を行うためのライブラリ
- **Scikit-learn**: 機械学習アルゴリズムが実装されたライブラリ

:::note info
インストールがまだの方は、次のコマンドで一括インストールできます！
:::

```bash
pip install numpy pandas matplotlib seaborn scikit-learn
```

# 3. 最初の機械学習モデルを構築してみよう
では、最初のモデルを構築してみましょう。ここでは「Irisデータセット」という有名なデータセットを使用します。

## Irisデータセットの構造
Irisデータセットには、3種類のアヤメの花(セットサ、日本アヤメ、ベルジカアヤメ)とそれぞれの特徴量が含まれています。

## 簡単な例
```python
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# データセットの読み込み
iris = load_iris()
X = iris.data
y = iris.target

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# モデルの訓練
model = LogisticRegression(max_iter=200)
model.fit(X_train, y_train)

# 予測と評価
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"モデルの精度: {accuracy:.2f}")
```

# 4. データの前処理と特徴量選択の重要性
データの前処理と適切な特徴量の選択は、機械学習において非常に重要です。これを怠ると、モデルの性能が著しく低下することがあります。

## データの前処理
以下のような前処理が一般的です。
- 欠損値の補完
- 異常値の処理
- データの正規化

## 特徴量選択
特徴量選択は、モデルに関連性の高い情報を提供し、学習を効率化します。

# 5. モデルの評価と改善
モデルの評価は、学習後の重要なステップです。異なる評価指標を用いてモデルの性能を分析し、改善点を見つけることで、より精度の高い予測が可能となります。

## 評価指標の例
- **精度(Accuracy)**: 正しく分類されたサンプルの割合
- **再現率(Recall)**: 実際にポジティブなサンプルのうち、正しく検出された割合
- **適合率(Precision)**: モデルがポジティブと判断したサンプルのうち、実際にポジティブな割合

```python
from sklearn.metrics import precision_score, recall_score

precision = precision_score(y_test, y_pred, average='macro')
recall = recall_score(y_test, y_pred, average='macro')

print(f"適合率: {precision:.2f}, 再現率: {recall:.2f}")
```

# 6. 実践編: 実データを使ってみよう
最後に、より複雑な実データを用いて実際にモデルを構築してみましょう。KaggleやUCI Machine Learning Repositoryなどのデータセットを活用するのも良い方法です。

## データセットの探し方
- **Kaggle**: コンペに参加しながらスキルを磨くことができるプラットフォーム
- **UCI Machine Learning Repository**: 様々な種類のデータセットが揃っているデータリポジトリ

:::note info
無料で利用できるデータセットが豊富にあります。自分の興味に合わせて選べるのが魅力！
:::

# まとめ
機械学習の基本概念から、実際のモデル構築までをステップバイステップで解説しました。Pythonという強力なツールを使えば、簡単に機械学習の世界に足を踏み入れることができます。この記事が、皆さんの機械学習の第一歩を手助けするものとなれば嬉しいです！
Squeezelite 出力デバイス指定方法

squeezelite 出力デバイス指定のメモ
将来の自分あてのメモ。なんか最近 FB の検索機能が怪しいので将来見つかるかどうかわからんけど。。。紙にも印刷しておこう。
新しい USB Audio デバイスを使う時には、まず、squeezelite -l で squeezelite が認識しているデバイス名を見る。で、
        -o hw:CARD=devicename
をコマンドラインオプションに指定する。
XMOS XS1-LS の場合、squeezelite -l の出力は以下。
        -o hw:CARD=X20
を指定すればOK。ふう、ひどく疲れた。X20 なんてわかんないよ、dmesg にも出てこないし。
# squeezelite -l
squeezelite: /usr/lib/libasound.so.2: no version information available (required by squeezelite)
squeezelite: /usr/lib/libasound.so.2: no version information available (required by squeezelite)
Output devices:
  null                           - Discard all samples (playback) or generate zero samples (capture)
  default:CARD=X20               - XMOS USB Audio 2.0, USB Audio - Default Audio Device
  sysdefault:CARD=X20            - XMOS USB Audio 2.0, USB Audio - Default Audio Device
  front:CARD=X20,DEV=0           - XMOS USB Audio 2.0, USB Audio - Front speakers
  surround21:CARD=X20,DEV=0      - XMOS USB Audio 2.0, USB Audio - 2.1 Surround output to Front and Subwoofer speakers
  surround40:CARD=X20,DEV=0      - XMOS USB Audio 2.0, USB Audio - 4.0 Surround output to Front and Rear speakers
  surround41:CARD=X20,DEV=0      - XMOS USB Audio 2.0, USB Audio - 4.1 Surround output to Front, Rear and Subwoofer speakers
  surround50:CARD=X20,DEV=0      - XMOS USB Audio 2.0, USB Audio - 5.0 Surround output to Front, Center and Rear speakers
  surround51:CARD=X20,DEV=0      - XMOS USB Audio 2.0, USB Audio - 5.1 Surround output to Front, Center, Rear and Subwoofer speakers
  surround71:CARD=X20,DEV=0      - XMOS USB Audio 2.0, USB Audio - 7.1 Surround output to Front, Center, Side, Rear and Woofer speakers
  iec958:CARD=X20,DEV=0          - XMOS USB Audio 2.0, USB Audio - IEC958 (S/PDIF) Digital Audio Output
JavaScriptでランダムな値を扱う

## はじめに
:::note info
(2024-07-21追記) コメントでご指摘いただいた内容について更新しました。
大変勉強になりました。ありがとうございます。
:::

時々使うかもしれないランダムな値の扱い方。
検索でも様々なものが出てきますが、自分なりに勉強したことをまとめます。

## 使用するプロパティ・メソッド
**`Math.random()` 静的メソッド**
今回のメイン。0以上1未満の乱数を返します。

**`Math.floor(num)` 静的メソッド**
num以下で最大の整数を返します。

**`length` プロパティ**
配列の要素の数を返します。

**`flat(depth)` メソッド**
配列を引数depthの深さだけフラット化したものを返します。
depthを省略した場合は1とみなします。

**`sort(fn)` メソッド**
ソート順を定義する関数fnに従って元の配列をソートし、その結果を返します。
fnの戻り値が正か負かによって、並びが変わります。

## ランダムな整数を取得する
:::note warn
以下の変数min, maxには整数が代入されることを想定しています。
:::
### 0以上max以下のランダムな整数を取得する
```js
const max = 100;
console.log(Math.floor(Math.random() * (max + 1)));
  // 例: 51
```

### min以上max以下のランダムな整数を取得する
```js
const min = -100;
const max = 100;
console.log(Math.floor(Math.random() * (max - min + 1)) + min);
  // 例: -88
```

## 配列からランダムな要素を取り出す
### 一次元配列からランダムな要素を取り出す
:::note
(2024-07-21追記) at()メソッドについてコメントでご紹介いただきました。これは引数を整数に変換して配列の添字とするので、以下のコードで同様の結果が得られるようです。
```js
console.log(array.at(Math.random() * array.length));
```
:::

```js
const array = ['Cannondale', 'Cervélo', 'Colnago', 'Canyon', 'Corratec'];
console.log(array[Math.floor(Math.random() * array.length)]);
  // 例: Cervélo
```

### 二次元配列からランダムな要素を取り出す
```js
const array = [
    ['Cannondale', 'EF Education-EasyPost'],
    ['Cervélo', 'Team Visma | Lease a Bike'],
    ['COLNAGO', 'UAE Team Emirates'],
    ['Canyon', 'Alpecin-Deceuninck'],
    ['Corratec', 'Team corratec - Vini Fantini'],
];

console.log(array[Math.floor(Math.random() * array.length)][0]);
  // 例: Canyon
```

:::note
### 二次元配列から完全ランダムに要素を取り出す
```js
const array = [
    ['Cannondale', 'EF Education-EasyPost'],
    ['Cervélo', 'Team Visma | Lease a Bike'],
    ['COLNAGO', 'UAE Team Emirates'],
    ['Canyon', 'Alpecin-Deceuninck'],
    ['Corratec', 'Team corratec - Vini Fantini'],
];
const flatArray = array.flat();

console.log(flatArray[Math.floor(Math.random() * flatArray.length)]);
  // 例: EF Education-EasyPost
```
:::

### オブジェクトの配列からランダムな要素を取り出す
```js
const array = [
    { bike: 'Cannondale', team: 'EF Education-EasyPost' },
    { bike: 'Cervélo', team: 'Team Visma | Lease a Bike' },
    { bike: 'COLNAGO', team: 'UAE Team Emirates' },
    { bike: 'Canyon', team: 'Alpecin-Deceuninck' },
    { bike: 'Corratec', team: 'Team corratec - Vini Fantini' },
];

console.log(array[Math.floor(Math.random() * array.length)].bike);
  // 例: Corratec
```

## 配列をランダムに並べ替える
### 一次元配列をランダムに並べ替える
:::note warn
(2024-07-21追記) このコードは並べ替え結果に偏りがあることについてコメントでご指摘いただきました。[新しい記事](https://qiita.com/ameRese/items/1138ee922539447dca5b "JavaScriptの配列をランダムに並べ替える")で偏りを解消したコードについて紹介しています。
:::

```js
const array = ['Cannondale', 'Cervélo', 'Colnago', 'Canyon', 'Corratec'];
console.log(array.sort(() => Math.random() - 0.5));
  // 例: ['Canyon', 'Colnago', 'Cervélo', 'Corratec', 'Cannondale']
```
二次元配列やオブジェクトの配列でも同様の手順で並べ替えることができます。

## おわりに
`Math.random()`と他のメソッドの組み合わせで、多様な処理を実現できそうだと感じました。
例えば配列から複数要素を取り出したり文字列をランダムに並べ替えたりすることも簡単にできそうです。
EC2でユーザーデータとCodeDeployの実行順序を制御する

# 概要
EC2起動時にユーザデータを使用して処理を実行させることができます。
また、オートスケーリンググループを使用してEC2を起動した場合は、ライフサイクルフックを利用してCodeDeployにデプロイを実行する事が可能です。

ユーザデータ実行中にCodeDeployを起動するのではなく、ユーザデータが終了した後にCodeDeployを起動したい時の設定方法を説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408925/426cc052-94f4-3842-5b65-bc80792fcdc8.png)


# 環境
以下の環境を想定します
- AWS
  - EC2(Linux)
  - オートスケーリンググループによりEC2を起動
  - CodeDeployでデプロイを実行

# 設定方法
CodeDeployを実行する場合は、対象となるEC2にCodeDeploy Agentのインストールを行います。
CodeDeploy Agentをユーザデータ終了後に起動する設定を実施します。


### 1. ユニットファイルのコピー
/usr/lib/systemd/system/ にあるCodeDeployのユニットファイルを
/etc/systemd/system/ にコピー

### 2.ユニットファイルの修正
[Unit]の項目目の下に Afterを追加します。
すでにAfterの行がある場合は（多分あるはず）、その行に cloud-final.service をスペース区切りで追記します。

``` 
[Unit]
After=cloud-final.service    # これを追加する
```

ユニットファイルの編集が完了したら、設定を有効にするためデーモンリロードします

```
sudo systemctl daemon-reload
```

これで順番の制御ができているか動作確認を行います。
CodeDeployに限らず、systemctlで起動しているサービスは順序の制御が可能ですので、他のサービスについても応用可能だと思います。



# 参考
- systemd 管理のサービスをcloud-init の後に実行する

https://oji-cloud.net/2022/06/30/post-7063/

- 10.6. systemd のユニットファイルの作成および変更

https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/7/html/system_administrators_guide/sect-managing_services_with_systemd-unit_files
【メモ】PostgreSQL初期設定【MacOS】

MacOSのローカル環境ででbrewコマンドを利用して、PostgreSQLに接続したい場合の設定
※Laravelアプリケーション利用を想定

```.env
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=your_database_name
DB_USERNAME=your_username
DB_PASSWORD=your_password
```

```sh
brew install postgresql
brew services start postgresql
brew services list

# DBに接続
psql postgres
```

```sh
# ユーザーを作成
CREATE DATABASE your_database_name;
CREATE USER your_username WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE your_database_name TO your_username;
```

```sh
# Laravelアプリケーション
php artisan config:cache
php artisan config:clear
```

```sh
# 作成したユーザーでDBに再度アクセスする
psql -U your_username -d your_database_name
```

```
# テーブル一覧を確認
\dt
```
Pythonの sendto 、send 、sendall の違い

## `sendto`

- **用途**: 主にUDPソケットで使うが、TCPソケットでも使用可能。
- **機能**: データを指定されたアドレスに送信する。
- **構文**: `sendto(bytes, address[, flags])`
  - `bytes`: 送信するデータ（バイト形式）。
  - `address`: 送信先のアドレス（IPアドレスとポート番号のタプル）。
  - `flags`: オプションのフラグ（省略可能）。
- **特徴**: コネクションレスプロトコル（UDP）に適している。

```python
import socket

# ソケット作成
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
address = ('localhost', 12345)

# データ送信
s.sendto(b'Hello, World!', address)
s.close()
```

## `send`

- **用途**: 主にTCPソケットで使用。
- **機能**: コネクションが確立された相手にデータを送信する。
- **構文**: `send(bytes[, flags])`
  - `bytes`: 送信するデータ（バイト形式）。
  - `flags`: オプションのフラグ（省略可能）。
- **特徴**: TCP接続でデータを送信するが、バッファサイズに制限があるため、全データを一度に送信できないことがある。

```python
import socket

# ソケット作成
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('example.com', 80))

# データ送信
s.send(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
s.close()
```

## `sendall`

- **用途**: 主にTCPソケットで使用。
- **機能**: すべてのデータが送信されるまでブロックする（部分送信の処理を内部で行う）。
- **構文**: `sendall(bytes[, flags])`
  - `bytes`: 送信するデータ（バイト形式）。
  - `flags`: オプションのフラグ（省略可能）。
- **特徴**: データ全体が送信されることを保証する。送信途中でエラーが発生した場合、例外を発生させる。

```python
import socket

# ソケット作成
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('example.com', 80))

# データ送信
s.sendall(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
s.close()
```

## 比較まとめ

| メソッド  | 主な用途          | 特徴                                                                                       |
|---------|-----------------|------------------------------------------------------------------------------------------|
| `sendto` | UDP、TCP          | データを指定されたアドレスに送信。コネクションレス通信に適している。                                      |
| `send`   | TCP              | コネクションが確立された相手にデータを送信。バッファサイズによる制限がある場合がある。                              |
| `sendall`| TCP              | データ全体が送信されることを保証。部分送信の処理を内部で行い、送信途中でエラーが発生した場合は例外を発生させる。            |
なぜターミナルはCtrl+Cで終了するのか？

## 読み飛ばしてください
おはようございます、しなもんです。

ターミナルみんな使ってますよね。
しかし今でも分からないことがあるんですよね。

**なんで`Ctrl+C`でターミナルが終了するの？**

多くの人にとって、GUIアプリケーションでは`Ctrl+C`はコピーのショートカットであるはずです。
しかし、ターミナルでは異なる役割を持っています。

この記事では、なぜターミナルで`Ctrl+C`が実行中のプログラムを終了させるショートカットとなっているのか、その歴史的背景と技術的な理由を探ってみます。

## ターミナルの歴史

まずはターミナルの歴史から簡単に見ていきましょう。
ターミナルの起源は、コンピューターの黎明期にまで遡ります。

1960年代、コンピューターは非常に大型で高価な機械でした。
ユーザーは**テレタイプ**と呼ばれる端末を通じてコンピューターと対話していました。
これらの端末は、タイプライターのような機械で、紙にコマンドを打ち込み、結果を印刷して表示しました。

1970年代に、UNIXオペレーティングシステムが開発されました。
UNIXは、**コマンドラインインターフェース**（CLI）を主要な操作方法として採用し、
「**シェル**」と呼ばれるプログラムを通じてユーザーとシステムのやり取りを行いました。

1990年代以降、LinuxやさまざまなUNIXライクなシステムが登場し、bashなどの高機能なシェルが普及しました。
Microsoftも2006年にPowerShellを導入し、Windowsでも強力なCLI環境が利用できるようになりました。

これらの歴史的な流れの中で、ターミナルの操作方法や規則が形成されていったわけです。

## 制御文字の概念

ターミナルが発展していくのに伴い、**制御文字**という概念が重要な役割を果たしました。
この時点で察した方もいるかもしれませんが、`Ctrl+C`がターミナルで終了を意味するのは、**制御文字の概念に由来しているわけです**。

ASCIIは7ビットの文字コードで、印刷可能な文字に加えて、32の制御文字を定義しています。
これらの制御文字は、テキストの構造や通信の制御に使用されます。

https://ja.wikipedia.org/wiki/%E5%88%B6%E5%BE%A1%E6%96%87%E5%AD%97

多くの制御文字は、キーボードの「Ctrl」キーと別のキーを組み合わせて入力します。
例えば、「Ctrl+C」は ASCII コードの 0x03 に対応し、これは **"ETX"**（End of Text）を意味します。

## Ctrl+Cの由来

`Ctrl+C`は制御文字であったわけです。
ではなぜターミナルでプログラムの終了を意味するようになったのでしょうか？

- **ASCII制御文字の"ETX"との関連**
"ETX"は先述した通り、本来はテキストデータの終了を知らせる役割を持っています。
ですが、初期のコンピュータやターミナルでは、
テキストデータとプログラム実行を明確に区別する仕組みがなかったため、
**ETXがプログラム実行の終了を知らせるために転用されるケース**がありました。
メモリ容量や処理能力が限られていたため、判別する仕組みを導入しなかったそうです。

- **なぜ"C"が選ばれたのか**
"C"は"Cancel"や"Control"の頭文字であり、直感的に「中断」や「制御」の意味を連想させやすいためであるようです。

:::note info
**ターミナルにおけるCtrl+Cの機能**

「Ctrl+C」が押されると、ターミナルはカーネルに対して現在フォアグラウンドで実行中のプロセスに割り込み信号を送るよう要求します。

この割り込み信号は「**SIGINT**」（Signal Interrupt）と呼ばれ、プロセスに対して実行を中断するよう通知します。

多くのプログラムはこの信号を受け取ると、適切にリソースを解放して終了してくれます。

:::

## 他の関連するターミナルショートカット

`Ctrl+C`以外にも、ターミナルでよく使われるショートカットがいくつかあります。

- **Ctrl+D（EOF）**: ファイルの終わり（End of File）を示します。多くのコマンドラインプログラムでは、入力の終了を意味します。

- **Ctrl+Z（一時停止）**: 実行中のプロセスを一時停止し、バックグラウンドに移動させます。

これらのショートカットも、ASCII制御文字に基づいていたわけでした。

## 現代のGUIアプリケーションとの違い

さて、ターミナルで`Ctrl+C`が終了を意味するのは、制御文字に由来する歴史的な理由があることが分かりました。
しかし、なぜ現代のGUIアプリケーションでは`Ctrl+C`がコピーのショートカットとして使われているのでしょうか？

- **GUIの発展**
グラフィカルユーザーインターフェース（GUI）が普及する中で、コピー＆ペーストのような一般的な操作にショートカットキーが割り当てられました。

- **操作哲学の違い**
ターミナルは主にテキストベースの入出力に特化しており、GUIとは異なる操作体系を持っています。
ターミナルでは、テキストの編集よりもプロセスの制御が重要な役割を果たすため、「Ctrl+C」は制御文字の意味そのままに、終了の意味を保持しています。

## 最後に

`Ctrl+C`がターミナルで終了を意味するのは、ASCII制御文字の概念に由来していたことが分かりました。分かってすっきり。
今では制御文字はあまり意識されないかもしれませんが、コンピューターの歴史と技術の基盤として重要な役割を果たしていたわけですね。
VBA100本ノック 30本目 名札作成

## 投稿マラソンのネタが尽きてきたので
### 古の会社には有益かもしれない
https://excel-ubara.com/vba100/VBA100_030.html

Excelの神髄 VBA100本ノックに初挑戦しました。

問題は名札作成ですが、アレンジして郵送時に使う宛名ラベルを作成するようになっています。もう業務で定期的に郵送する会社は減っているかと思いますので、バリバリにDXが進んでいるイケてる会社にお勤めの方にはほとんど意味のないコードになります。

公式の解答とは全くかけ離れたコードが完成しました。^^;
コードを書く前に、公式の解答をカンニングしましたが、私の足りない頭では理解できませんでした^^;

行番号が奇数ならラベルシートのA列、偶数ならB列に転記されるという単純な動きです。


```vb
Option Explicit

Sub raberutenki()
  
  Dim i As Long
  Dim j As Long
  Dim LastRow As Long
  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Set ws1 = Sheets("Sheet1")
  Set ws2 = Sheets("リスト")
  LastRow = ws2.Cells(Rows.Count, 1).End(xlUp).Row
  
  j = 1
  
  For i = 2 To LastRow
  
    If ws2.Cells(i, 1).Row Mod 2 = 0 Then 'リストの行番号が偶数なら
    
    'ラベルシートA列に転記
    ws1.Cells(j, 1) = ws2.Cells(i, 2) & vbCrLf & vbCrLf & ws2.Cells(i, 3) & _
                           ws2.Cells(i, 4) & vbCrLf & ws2.Cells(i, 5) & _
                           vbCrLf & ws2.Cells(i, 6) & " " & "さま"
                         
    j = j + 1
    
    End If
                           
  Next i
  
  i = 0: j = 0
  
  j = 1
  
  For i = 2 To LastRow
  
    If ws2.Cells(i, 1).Row Mod 2 <> 0 Then 'リストの行番号が奇数なら
    
    'ラベルシートB列に転記
    ws1.Cells(j, 2) = ws2.Cells(i, 2) & vbCrLf & vbCrLf & ws2.Cells(i, 3) & _
                           ws2.Cells(i, 4) & vbCrLf & ws2.Cells(i, 5) & _
                           vbCrLf & ws2.Cells(i, 6) & " " & "さま"
                         
    j = j + 1
    
    End If
                           
  Next i
  
End Sub
```
### 実行時の挙動

宛名リスト
![100本ノック30-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812230/28e7ac85-b5ed-b0bb-8b06-79f18307ebf7.png)

宛名ラベルのセルの書式
左詰め インデント2
行の高さ 155.00
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812230/83253d88-25a9-48a8-7aa5-d76beeccd44a.png)

ビフォーアフター
![100本ノック30-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812230/69f2e024-0f13-fb40-81b0-34bdc1221563.png)
Mongooseの基本を簡潔に

# Mongooseを使ってみよう：MongoDBとのデータ操作を簡単に！

Mongooseは、Node.js環境でMongoDBを扱うためのオブジェクトデータモデリング（ODM）ライブラリです。Mongooseを使用することで、スキーマを定義してデータをバリデート、クエリ、保存、削除することが簡単にできます。本記事では、Mongooseの基本的な使い方を紹介します。

【公式ドキュメント】

https://mongoosejs.com/docs/api/mongoose.html

## インストール
まず、Mongooseをプロジェクトにインストールする必要があります。以下のコマンドを使用してインストールします。

```bash
npm install mongoose
```
基本的な使い方
### 1. MongoDBへの接続
Mongooseを使用する前に、MongoDBデータベースに接続する必要があります。以下は、Mongooseを使用してMongoDBに接続する基本的なコードです。

```javascript
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mydatabase', {
  useNewUrlParser: true,
  useUnifiedTopology: true
}).then(() => {
  console.log('MongoDBに接続されました');
}).catch(error => {
  console.error('MongoDB接続エラー:', error);
});
```
### 2. スキーマとモデルの定義
Mongooseでは、スキーマを定義してモデルを作成します。以下は、ユーザースキーマの例です。

```javascript
const { Schema, model } = mongoose;

const userSchema = new Schema({
  userName: { type: String, required: true },
  userAge: { type: Number, required: true },
  userEmail: { type: String, required: true, unique: true }
});

const UserModel = model('User', userSchema);
```
### 3. データの作成
定義したモデルを使用してデータを作成することができます。以下は、ユーザーを新規作成する例です。

```javascript
const newUser = new UserModel({
  userName: '太郎',
  userAge: 30,
  userEmail: 'taro@example.com'
});

newUser.save()
  .then(createdUser => {
    console.log('ユーザーが作成されました:', createdUser);
  })
  .catch(error => {
    console.error('ユーザー作成エラー:', error);
  });
  ```
### 4. データの取得
モデルを使用してデータをクエリすることもできます。以下は、すべてのユーザーを取得する例です。

```javascript
UserModel.find()
  .then(allUsers => {
    console.log('ユーザー一覧:', allUsers);
  })
  .catch(error => {
    console.error('データ取得エラー:', error);
  });
  ```
### 5. データの更新
既存のデータを更新することも可能です。以下は、ユーザーの年齢を更新する例です。

```javascript
UserModel.updateOne({ userEmail: 'taro@example.com' }, { userAge: 31 })
  .then(updateResult => {
    console.log('ユーザーの更新結果:', updateResult);
  })
  .catch(error => {
    console.error('データ更新エラー:', error);
  });
  ```
### 6. データの削除
最後に、データを削除する方法を紹介します。以下は、特定のユーザーを削除する例です。

```javascript
UserModel.deleteOne({ userEmail: 'taro@example.com' })
  .then(deleteResult => {
    console.log('ユーザーの削除結果:', deleteResult);
  })
  .catch(error => {
    console.error('データ削除エラー:', error);
  });
  ```
## まとめ
Mongooseは、MongoDBを扱うための強力で使いやすいライブラリです。スキーマを定義し、簡単にデータを操作することができます。

# 【参考】
https://mongoosejs.com/docs/api/mongoose.html
[備忘録]Futureって何？[Dart]

非同期関数でセットで出てくるFutureについて軽く書き残します。

非同期関数の一つです。もう一個はasync・awaitを使用する方法パターンもあります。

非同期処理の実行完了後の未来において、実行結果を格納するための箱のようなものがFuture。asyncはawaiteで終わるまで待つがFuutreはThenで終わった後の処理を書くイメージ

`Future<int>`とするとreturnでintのデータを返すことになる。
OSCTF 2024 Writeups

# はじめに
OSCTF 2024に参加してきました。
結果は約740チーム中346位でした。
個人的にWebのAction Notesが解けなかったのが悔しかったです。
大会はJeopardy形式ではあるものの、ソースコードから脆弱性を見つけるようなものではありませんでした。
そういう意味ではHTBの問題に似ています。
今回は私が解いた問題の中で面白かったものを解説していきます。

# Forensics

## The Lost Image Mystery

image.pngが渡されます。
この画像はこのままだと開けないようです。
fileコマンドとhexeditコマンドで確認してみたところ、マジックナンバーが適切ではないような気がしたので
ここを直せば、画像が開けるようになり、フラグが読み取れそうです。

![Screenshot 2024-07-14 at 17.36.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/81bcf8f3-3c47-1090-1848-64589abeb4b5.png)

![Screenshot 2024-07-14 at 17.39.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/e5c7bc2a-1141-5900-cedf-27b94175c79f.png)

試しにこの画像をJPEGファイルとして修復しようと試みました。
この画像ファイルだとSOI(Start Of Image),APP0(Application Segment 0)マーカが記述されていなかったので
最初の数バイトを以下のように書き換えます。
```
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 00 00
```
すると画像が開けるようになり、そこにフラグがありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/21fd15f1-4a6b-ee28-fd21-1820b158238b.png)

## The Hidden Soundwave

Alan Walker.mp3という音声ファイルが渡されるので、一旦聴いてみます。
すると最後の方に奇妙な音声が混ざっていました。
早速Audacityのspectrogramモードで解析してみます。
すると、そこにフラグがありました。

![Screenshot 2024-07-14 at 17.59.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/4580508a-78bb-9b79-9a8d-c9e87b57ce09.png)

## Seele Vellorei

wordファイルが渡されたので開いてみます。

![Screenshot 2024-07-14 at 18.01.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/182ce1f9-3d4a-2a25-e1e0-23cd1be3d516.png)

この時点ではあまり気になるところはありません。
ワードファイルは圧縮ファイルとして解凍することが可能です。
そこで、解凍したファイルの中身にフラグが入っていないか確かめてみます。
案の定document.xmlの中にフラグが入っていました。

![Screenshot 2024-07-14 at 18.05.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/c015cb1d-b65f-ed66-4158-bb17363880ea.png)

# Web

## Action Notes

問題で配布されたURLに行ってみると、RegisterとLoginページに推移するボタンが置かれているだけでした。
Registerページでadminとして登録しようとすると、adminは既に登録済みと言われてしまいました。
代わりに他のIDで登録し、それでログインしてみました。
するとnotesというページに推移しました。
ここでは任意の文字列をノートとして登録しておけるようです。
色々パラメータをいじっていると、エラーログがレスポンスとして帰ってきました。
どうやらこれはFlaskで動いていて、デバッグモードが有効になっているようです。

![Screenshot 2024-07-14 at 18.15.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/f1555418-0520-d05b-9c34-8c0edb7de59a.png)

そのエラーの中にそれの原因となったソースコードの部分が記述されていたので見てみると
面白い箇所がありました。

![Screenshot 2024-07-14 at 18.16.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/c07b21ac-ff3f-6b69-58f8-8e2064f2e60e.png)

登録したノートの値をテンプレートエンジンで表示しています。
SSTIが可能なのではと思い、試してみたのが下の図です。

![Screenshot 2024-07-14 at 18.12.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510659/b3dd5361-fba3-6064-313c-84e34d4e52dd.png)

ですが、どれも上手くいきませんでした。
このウェブサイトはデバッグモードが有効になっていることからconsoleページへのアクセスが可能になっています。
そこで、PINコードを推測し、consoleページへのアクセスを奪おうと思いましたが
それには必要な情報をパストラバーサルか何かで取得する必要があります。
私はその方法が分からず、結局時間内に解くことはできませんでした。

# おわりに

今回は順位としてはあまり良い結果ではありませんでしたが、ローカル環境での攻撃検証が
以前より柔軟に行えるようになっていた自分に驚きました。
特にAction Notesでは、実際にflaskでWebサイトを立ち上げ、どのような機能が脆弱になるかを直感的に理解することができました。
[備忘録]flutterアプリ名の変更

- Androidの場合
 android/app/src/main/AndroidManifest.xmlの android:labelを書き換え
- iOSの場合
 ios/Runner/info.plistの keyがCFBundleNameの文字列を書き換え

pubspec.yamlのnameを変えてしまってもOKだが、lower_case_with_underscoresのマナーに触れる。そしてキャメル記法で書かなくてはいけない
[備忘録]dart:convertは何？


Dart の標準ライブラリの一つで、`JSON`やUTF-8などのエンコーディング形式を扱うための機能を提供しています。Flutterアプリ開発において、データをネットワーク越しに送受信する場合や、ローカルに保存する際にこのライブラリが非常に役立ちます。
Pandas: ストリングの置換

'abc' というストリングを総て、'01234' に置き換える方法

## プログラム

```py:str_replace.py
#! /usr/bin/python
#
#	str_replace.py
#
#					Jul/14/2024
#
import pandas as pd

#
data = {'col1': ['abc', 'xyz', 'abc', 'pqr', '923'],
        'col2': ['abc', 'def', 'abx', 'ghi', '654'],
        'col3': ['abc', 'abc', 'abc', 'abc', '231']}
df = pd.DataFrame(data)

print(df)
#
str_src = 'abc'
str_target = '01234'
df = df.map(lambda x: str_target if x == str_src else x)

print(df)
```

## 実行結果

```text
$ ./str_replace.py 
  col1 col2 col3
0  abc  abc  abc
1  xyz  def  abc
2  abc  abx  abc
3  pqr  ghi  abc
4  923  654  231
    col1   col2   col3
0  01234  01234  01234
1    xyz    def  01234
2  01234    abx  01234
3    pqr    ghi  01234
4    923    654    231
```
WindowsにFFmpegをインストールする方法

この記事では、WindowsにFFmpegをインストールするための複数の方法を紹介します。FFmpegは強力な動画・音声処理ツールですが、Windowsへのインストール方法がわかりにくい場合があります。

## 目次
1. [方法1: Wingetでインストール](#方法1-wingetでインストール)
2. [方法2: 手動インストール](#方法2-手動インストール2025年4月時点)
3. [方法3: Chocolateyでインストール](#方法3-chocolateyでインストール)
4. [インストールの確認](#インストールの確認)
5. [おわりに](#おわりに)

## 方法1: Wingetでインストール
Microsoftの公式パッケージマネージャー `winget` を使用すると、最も簡単にインストールできます：

1. 管理者権限でPowerShellまたはコマンドプロンプトを開きます。
2. 次のコマンドを実行します：
```powershell
winget install --id=Gyan.FFmpeg -e
```
3. このコマンドは、Gyan.devが提供するFFmpegのビルドをインストールします。FFmpegの公式サイトでも紹介されているビルドです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/vRPEgdiUvoU?si=7f3d76zxVvJKUuwl" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

## 方法2: 手動インストール（2025年4月時点）
手動でインストールする方法は以下の通りです：

1. [FFmpegの公式サイト](https://ffmpeg.org/)にアクセスします。
2. 「Get packages & executable files」セクションから、**Windows builds from gyan.dev** または **BtbN's FFmpeg Builds** を選びます。
   - FFmpeg公式サイト自身はバイナリを提供しておらず、外部サイト（例：gyan.devやBtbN）へのリンクを案内しています。
   
3. 移動先サイトで、Windows用の最新ビルド（例："release essentials"や"full build"）をダウンロードします。
4. ダウンロードした7zファイルを解凍します（7-Zipなどの解凍ソフトが必要です）。
5. 解凍したフォルダを任意の場所（例：`C:\FFmpeg`）に移動します。
6. システム環境変数のPATHに、FFmpegの実行ファイルがあるbinフォルダのパス（例：`C:\FFmpeg\bin`）を追加します。

### 環境変数の設定方法：
- Windowsキー + Rを押し、「sysdm.cpl」と入力してシステムのプロパティを開きます。
- 「詳細設定」タブ→「環境変数」をクリックします。
- 「システム環境変数」の「Path」を選択し、「編集」をクリックします。
- 「新規」をクリックし、FFmpegのbinフォルダのパスを追加します。
- 「OK」を押して全ての画面を閉じます。

## 方法3: Chocolateyでインストール
別のパッケージマネージャーを使った方法として：

1. [Chocolatey](https://chocolatey.org/)というパッケージマネージャーをインストールします。
2. 管理者権限でPowerShellを開きます。
3. 次のコマンドを実行してFFmpegをインストールします：
```powershell
choco install ffmpeg
```
これで、FFmpegが自動的にインストールされ、PATHにも追加されます。

## インストールの確認
インストールが完了したら、以下の手順で確認します：

1. コマンドプロンプトまたはPowerShellを開きます。
2. 次のコマンドを入力します：
```
ffmpeg -version
```
3. FFmpegのバージョン情報が表示されれば、インストールは成功です。
4. 表示されない場合は、環境変数 `PATH` にFFmpegの `bin` ディレクトリが正しく追加されているか確認してください。

## おわりに
FFmpegは非常に強力なツールですが、Windowsへのインストールは少し手間がかかる場合があります。この記事で紹介した方法を参考に、ぜひFFmpegをインストールして活用してみてください。

質問やコメントがあれば、お気軽にコメント欄でお聞かせください。Happy coding!

## 免責事項
- 本記事の作成にあたり、文章や図解の生成にClaude Sonnetを活用しました。最終的な編集と確認は筆者が行っています。

- この記事の手順に従ってインストールを行った場合に発生する可能性のある問題については、個別の対応ができかねます。インストール作業は、ご自身の責任と判断で行っていただきますようお願いいたします。

- なるべく最新の情報に基づいて記事を作成していますが、ソフトウェアのアップデートやウェブサイトの変更により、記載内容が陳腐化してしまう可能性があります。その場合はご容赦ください。最新の正確な情報は、常に公式サイトでご確認いただくことをお勧めします。

#FFmpeg #Windows #インストール
【Linux】カーネルパラメータのチューニング


## 背景

大規模なクローリングを行うバッチシステムを構築している際、TCPコネクションが同時に多数確立することでTIME_WAIT状態のものでいっぱいになっていました。、これにより、利用可能なエフェメラルポートが枯渇してクローリングの時間が長くなりすぎていたので、カーネルパラメータをチューニングしてみました。

参考
* TCPとTIME_WAIT : https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux
* TCPの各種状態について : https://hana-shin.hatenablog.com/entry/2022/08/21/214706


## 確認
* 使用ポート数
    * `netstat | grep tcp | wc -l`などで確認可能
* TIME_WAIT
    * `netstat -nat | grep TIME_WAIT | wc -l`などで確認可能
    * 自身のWEBサーバーでlistenしている場合は`grep -v :80`や`grep -v :443`などで除く必要がある
* カーネルパラメータ
    * `cat /etc/sysctl.conf`で確認
    * `sysctl -a`で一覧確認
    * `sysctl -n {param}`で対象パラメータの設定値を確認

# カーネルパラメータ
今回のような事象に有効なlinuxカーネルのパラメータについて
デフォルトはcentos 7.9.2009での値

### net.core.somaxconn
* default : `128`
* description : ESTABLISHED状態のソケット上限
* note : アプリケーション側での設定で接続数増やそうと頑張ってもここを増やさないと変わらない

### net.ipv4.tcp_max_syn_backlog
* default : `512`
* description : SYN_RECEIVED状態のソケット上限
* note : `net.core.somaxconn`の上限値が優先される

### net.ipv4.tcp_tw_reuse
* default : `2`
* description : TIME_WAIT状態から1秒以上経過したソケットのポートを新しい接続に再利用する

### net.ipv4.tcp_fin_timeout
* default : `60`
* description : FIN_WAIT_2のタイムアウト設定
* note : TIME_WAITのタイムアウトではない.相手から最後のFINパケットを受け取るまで待機し、TIME_WAITに移行する

### net.ipv4.tcp_max_tw_buckets
* default : `NR_FILE*2`
* description : システムが許容する TIME_WAIT 状態にあるソケットの最大数

### net.ipv4.ip_local_port_range
* default : `32768 60999`
* description : 使用可能なポート範囲
* note : netstatで確認した大まかなポート使用数が設定値より十分に小さければ問題ない. 上限は`1024 65535`

### net.ipv4.ip_local_reserved_ports
* default : `-`
* description : 予約済みのポート.port_rangeを広げた場合などに使用

# 設定
上記を踏まえて高負荷条件下での設定値を考えます
1. `net.ipv4.tcp_tw_reuse`を1にする
    * TIME_WAIT状態が溜まっているような場合はこれがよく効きます
2. `net.core.somaxconn`を増やす
    * こちらはデフォルト値が128と少ないので増やしたほうがいい
    * よく見る設定値としては1024や2048でしょうか
    * `net.ipv4.tcp_max_syn_backlog`も一緒に増やす
3. `net.ipv4.tcp_fin_timeout`を減らす
    * FIN_WAIT_2状態が溜まっているような場合には有効
    * 設定値は状況によって変化しうる
        * e.g. バッチなら5秒, WEBサーバーなら30秒とか


### 一時的に設定する例
`sysctl -n {name}={value}`
```
# sysctl -w net.core.somaxconn=1024
net.core.somaxconn=1024
# sysctl -w net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_reuse=1
# sysctl -w net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_fin_timeout=30
```

### 永久的に設定する場合
1. `vi /etc/sysctl.conf` : 設定値の書き換え
2. `sysctl -p` : 更新の反映
```
# vi /etc/sysctl.conf
# cat /etc/sysctl.conf
net.core.somaxconn = 1024
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=30
# sysctl -p
```

例のようにとりあえずシステムに影響のない範囲から始めて、様子見ながら状況に応じて他のパラメータなども設定していくという流れが良いかと思われます。

## 結果
自分の場合、アプリケーション側でのコネクションプーリングに加え上記の設定を反映させることでクローリング終了までの時間が50h -> 7hくらいに大幅に改善しました。
【Unity】SingletonMonoBehaviourを実装しよう

# SingletonMonoBehaviourとは？

**異なるシーン間で唯一のインスタンスを維持・管理するために設計されたクラスです。
このクラスはシーン遷移に影響されず、データや設定の一貫性を保つのに役立ちます。**

これだけ聞くと難しく感じるかもしれませんが、
平たく言ってしまえば「Singleton + MonoBehaviour」です。

つまり、**MonoBehaviourの機能を活用しながら、
Unityのシーン間で唯一のインスタンスを管理するシングルトンを作ろう**というものです。

シングルトンってなんだ？という方は、[こちらの記事](https://qiita.com/GameDevEgg/items/773a68314ca89c40c578) を参考にしてみて下さい。

# SingletonMonoBehaviourの特徴

SingletonMonoBehaviour には3つの特徴があります。

<INS> **1．MonoBehaviourを継承** </INS>

-> Unityのライフサイクルイベントを利用でき、DDOLの設定も可能になる。

<INS> **2．シングルトンパターンの実装** </INS>

-> 通常のシングルトンパターンと同様に、唯一のインスタンスを保持する。

<INS> **3．DDOLに設定** </INS>

-> シーン遷移時に破棄されないように設定し、ゲームを通してインスタンスを保持する。

# SingletonMonoBehaviourクラスを実装する

<details><summary>上記3つの特徴に沿って実装したクラスがこちらです。</summary>

```cs
using UnityEngine;

public class SingletonMonoBehaviour<T> : MonoBehaviour where T : MonoBehaviour
{
    // シングルトンのインスタンス
    private static T instance;

    public static T Instance
    {
        get
        {
            if(instance == null)
            {
                // シーン内からゲームオブジェクトを検索
                instance = FindObjectOfType<T>();

                if(instance == null )
                {
                    // インスタンスが見つからなかった場合、新しいゲームオブジェクトを作成
                    GameObject singletonObject = new GameObject();
                    instance = singletonObject.AddComponent<T>();
                    singletonObject.name = typeof(T).ToString() + " (Singleton)";

                    // シーン遷移時にオブジェクトを破棄しないように設定
                    DontDestroyOnLoad(singletonObject);
                }
            }
            return instance;
        }
    }

    // Awakeメソッドで重複インスタンスをチェック
    protected virtual void Awake()
    {
        if (instance == null)
        {
            instance = this as T;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}
```
</details>

先ほど紹介した記事で実装したシングルトンと共通している部分がほとんどです。
大きな違いと言えば、ジェネリックなクラスになっていることです。
これにより、あらゆるクラスに対して同じシングルトンの機能を提供します。

最後までご覧いただきありがとうございました :laughing:
viとvimって区別しなくてよくないですか？

# はじめに
突然ですが、皆さんはエディタのviやvimをご存じでしょうか？
まぁ大半の人は一度くらい触れたことがあるはずですのでご存知かと思います。

本やドキュメント、様々な場所でこれらのコマンドを見かけますが、その所々でviであったりvimであったりします。
しかしながら、実際に実行してみると似たようなインターフェースで似たような機能があります。

今回の記事ではこのviとvimについて書いていきます。

# viとvimの違い
viは、1976年にBill Joyによって開発された歴史のあるエディタで、Unixオペレーティングシステムの標準エディタとして広く使用されてきました。

一方、vimは「Vi IMproved」の略で、1991年にBram Moolenaarによって開発されたviの拡張版です。
vimはviのすべての機能を持ちながら、さらに多くの機能や改良が加えられています。
シンタックスハイライトや自動補完、拡張機能的なものがそれですね。

# viとvimって区別しなくてよくない？
商用Unixを使う機会はほとんどなく、Linuxを利用する限りにおいて、viもvimも基本操作はほぼ同じなので、区別しなくても困ることは特筆ないでしょう。
しかし、実際にはviとvimは別物であって、そのことは一部のBSDユーザーにとってめちゃ重要らしいです。

とはいえ、一般ユーザーにとっては、viとvimの違いを気にするよりも、自分が使いやすいエディタを選ぶことが大切な気がします。

ちなみに、Ubuntuにおいてはviとvimの実態は全く一緒だったりします。
```bash
# vim
chan-mai@test-sandbox-007:~# which vim
/usr/bin/vim

chan-mai@test-sandbox-007:~# ls -hl /usr/bin/vim
lrwxrwxrwx 1 root root 21 Nov 23  2023 /usr/bin/vim -> /etc/alternatives/vim

chan-mai@test-sandbox-007:~# ls -hl /etc/alternatives/vim
lrwxrwxrwx 1 root root 18 Nov 23  2023 /etc/alternatives/vim -> /usr/bin/vim.basic

# vi
chan-mai@test-sandbox-007:~# which vi
/usr/bin/vi

chan-mai@test-sandbox-007:~# ls -hl /usr/bin/vi
lrwxrwxrwx 1 root root 20 Nov 23  2023 /usr/bin/vi -> /etc/alternatives/vi

chan-mai@test-sandbox-007:~# ls -hl /etc/alternatives/vi
lrwxrwxrwx 1 root root 18 Nov 23  2023 /etc/alternatives/vi -> /usr/bin/vim.basic
```

どちらも`/usr/bin/vim.basic`を参照してるんですよね。

これといったソースはありませんが、最近の環境だとエイリアス張ってるだけの偽物viは結構あるように思えます。


# どっちを使うべき？
どっちでもいいです。好きな方を使ってください。
「viを使っているつもりが、実はvimだった」みたいなこと、割とよくありますからね。

# さいごに
結局のところ、viとvimをそこまで厳密に区別する必要はないように私は思います。
最近だと、VScodeやらJETBRAINS IDEやらばっかで、そもそもvimを触ったことすら無い人も結構居るのではないでしょうか。
慣れてしまえばちょっとvimもいいんですけどね。

「viのつもりでvimを使うと互換ない部分もあるから～」みたいなことを言っているクラスタにおいては区別をした方がいいかもしれません。
おそらく燃えます。

それでは。
react-router-domを使ったViteアプリをGitHub Pagesで公開する方法【備忘録】

# 概要
先日、react-router-domを使用したViteアプリケーションをGitHub Pagesで公開した際に、想定していたアプリケーションの画面ではなく、ただ真っ白な画面が表示されてしまいました。
次回以降、同じ現象で困らないようにするため、この現象に対する対処法をまとめます。

# 方法
vite.config.tsファイルとmain.tsxファイルにbaseの設定を追記します。
<リポジトリ名>の部分は、GitHubのリポジトリ名で置き換えてください。
```diff_typescript:vite.config.ts
import path from "path"
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
+  base: '/<リポジトリ名>/',
})

```

```diff_typescript:main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { BrowserRouter } from "react-router-dom";


ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <BrowserRouter 
+    basename={import.meta.env.DEV ? "/" : "<リポジトリ名>"}
    >
      <App />
    </BrowserRouter>
  </React.StrictMode>
)

```
参考：[Viteによって作成したReactアプリをGithub Pagesを使ってデプロイ！](https://qiita.com/otohusan/items/dca3aef745674f2eb642#react-router-%E3%81%AE%E5%88%A9%E7%94%A8%E8%80%85%E5%90%91%E3%81%91)

package.jsonのbuildコマンドを書き換え、rebuildのコマンドを追記します。
```diff_json:package.json
{

// 省略

"scripts": {
    "dev": "vite",
-    "build": "tsc -b && vite build",
+    "build": "tsc -b && vite build && cp -r dist docs",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview",
+    "rebuild": "vite build && rm -R docs && cp -r dist docs"
  },
  
// 省略

}
```
参考：[ReactをGitHub Pagesにデプロイしよう〜Vite編〜](https://qiita.com/tat_mae084/items/4051c61926dc8165e80b#32-packagejson%E3%82%92%E7%B7%A8%E9%9B%86)

ターミナルで`npm run build`(2回目以降のビルド時は`npm run rebuild`)を実行してビルドしたのち、GitHubへアップロードします。

リポジトリページでSettingsタブを選択し、サイドメニューのPagesを選択します。Build and deploymentのbranchの項目を「main」ブランチの「/docs」に設定して「Save」ボタンを押下します。
![GitHub_Pages_Settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/471406e8-ee00-8386-6fc5-4eaa2a87f534.png)

Actionsタブでワークフローに✅がついたら、ワークフロー詳細画面の「deploy」カードに表示されているURLにアクセスし、想定通りのページが表示されているかどうかを確認します。
![GitHub_Pages_Actions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/c9e83e5e-4a1f-f879-438c-00b7ba0dd67d.png)
ITパスポート コンピュータの形態

・処理形態
・集中処理
１台の大型コンピュータに複数の端末を接続し、その大型コンピュータで集中して処理させる形態

・分散処理
複数のコンピュータをネットワークに接続し、処理を分担させる形態

・クライアントサーバシステム
サービスを依頼するクライアントと、サービスを提供するサーバとに役割分担した形態

・主なサーバ
Webサーバ、メールサーバ、データベースサーバ、ファイルサーバ、プリントサーバ

・ブレードサーバ
CPUやメモリ、HDDなどを搭載したボード型のコンピュータを、専用の筐体のスロットに複数差し込んで使用するサーバ

・シンクライアントサーバ
クライアントPCの機能を最小限にした形態
OSやアプリケーションをサーバで一元管理する
データもサーバに保存する

・VDI
クライアントPCにOSやアプリケーションをインストールせずサーバ上にクライアントPCのデスクトップ環境を集約して、クライアントPCからリモートで操作する方式

・NAS
LANに直接接続される記憶装置で、複数のPCから共有可能なファイルサーバ専用機

・コンピュータの接続形態
・ピアツーピア
ネットワークに接続されているコンピュータ同士が、それぞれのデータなどをお互いに対等な関係で利用する形態
・スタンドアローン
コンピュータをネットワークに接続せず、単独で利用する形態

・利用形態
・バッチ処理（一括処理）
データを一定期間、一定量をまとめてから処理する形態

・リアルタイム処理（即時処理）
処理の依頼があると、即時に処理する形態

・対話型処理
利用者が、ディスプレイ上に表示されたアイコンを選択するなど、コンピュータと情報のやり取りを行い、人間の判断を加えながら処理する形態
Python pydubで始めるサンプリング: 既存の楽曲から新しい音楽を作る

## はじめに

サンプリングは現代音楽制作において欠かせない技術の一つです。既存の楽曲から一部を切り取り、それを新しい文脈で使用することで、独創的な音楽作品を生み出すことができます。本記事では、Pythonの音声処理ライブラリpydubを使用して、サンプリングの基本から新しい楽曲の作成までを解説します。

## 目次

1. サンプリングの基本概念
2. pydubのセットアップ
3. 音声ファイルの読み込みと基本操作
4. サンプルの切り出しとループ作成
5. 複数のサンプルの組み合わせ
6. エフェクトの適用
7. 最終的な楽曲の作成
8. 法的・倫理的考慮事項

## 1. サンプリングの基本概念

サンプリングとは、既存の音源から一部を抽出し、新しい楽曲の中で再利用する技術です。ヒップホップやエレクトロニック音楽で広く使われており、クリエイティブな表現方法として確立されています。

## 2. pydubのセットアップ

まず、pydubをインストールしましょう：

```bash
pip install pydub
```

注意: pydubはFFmpegに依存しているため、事前にFFmpegをインストールしておく必要があります。

## 3. 音声ファイルの読み込みと基本操作

pydubを使って音声ファイルを読み込み、基本的な操作を行います：

```python
from pydub import AudioSegment

# 音声ファイルの読み込み
song = AudioSegment.from_mp3("original_song.mp3")

# 音量の調整
louder_song = song + 6  # 6dB増加

# 特定の部分を切り出す（3秒から5秒まで）
clip = song[3000:5000]

# 保存
clip.export("sample.mp3", format="mp3")
```

## 4. サンプルの切り出しとループ作成

楽曲から特定の部分を切り出し、それをループさせてビートを作ります：

```python
def create_loop(audio, start_ms, end_ms, num_loops):
    loop_sample = audio[start_ms:end_ms]
    return loop_sample * num_loops

# 2秒から3秒の部分を8回ループ
drum_loop = create_loop(song, 2000, 3000, 8)
drum_loop.export("drum_loop.mp3", format="mp3")
```

## 5. 複数のサンプルの組み合わせ

異なる楽曲から切り出したサンプルを組み合わせて、新しいトラックを作成します：

```python
song1 = AudioSegment.from_mp3("song1.mp3")
song2 = AudioSegment.from_mp3("song2.mp3")

bass_sample = song1[1000:3000]
melody_sample = song2[5000:7000]

# サンプルを組み合わせる
combined = bass_sample.overlay(melody_sample)

# 4回繰り返す
new_track = combined * 4
new_track.export("new_track.mp3", format="mp3")
```

## 6. エフェクトの適用

サンプルにエフェクトを適用して、よりクリエイティブな音作りを行います：

```python
from pydub.effects import low_pass_filter, high_pass_filter, speed_change

# ローパスフィルター
low_bass = low_pass_filter(bass_sample, 800)

# ハイパスフィルター
high_melody = high_pass_filter(melody_sample, 1500)

# ピッチ変更
pitched_melody = speed_change(melody_sample, 0.8)  # ピッチを下げる

# エフェクトを適用したサンプルを組み合わせる
effect_track = low_bass.overlay(high_melody).overlay(pitched_melody)
effect_track.export("effect_track.mp3", format="mp3")
```

## 7. 最終的な楽曲の作成

これまでの要素を組み合わせて、最終的な楽曲を作成します：

```python
def create_song():
    intro = drum_loop[:4000]  # イントロ
    verse = new_track[:8000]  # ヴァース
    chorus = effect_track[:8000]  # コーラス
    
    # 楽曲構成: イントロ -> ヴァース -> コーラス -> ヴァース -> コーラス
    song = intro + verse + chorus + verse + chorus
    
    # フェードアウト
    song = song.fade_out(duration=3000)
    
    return song

final_song = create_song()
final_song.export("final_sampled_song.mp3", format="mp3")
```

## 8. 法的・倫理的考慮事項

サンプリングを行う際は、著作権法を遵守することが重要です：

1. 可能な限り、著作権フリーの音源や、適切にライセンスされた音源を使用しましょう。
2. 商用利用の場合は、原曲の権利者から許可を得る必要があります。
3. フェアユースの概念（教育目的や批評目的での使用）を理解しておくことも大切です。
4. 自作の楽曲や、パブリックドメインの楽曲を使用するのが最も安全です。

## まとめ

pydubを使用したサンプリングの基本テクニックを紹介しました。これらの技術を組み合わせることで、既存の楽曲から新しい、独創的な音楽を作り出すことができます。

サンプリングは単に既存の音楽の一部を切り取るだけでなく、それを新しい文脈で再解釈し、全く新しい作品として生まれ変わらせる芸術的な行為です。技術的なスキルと創造性を組み合わせることで、無限の可能性が広がります。

ぜひ、この記事で学んだテクニックを基に、自分だけのユニークな楽曲制作に挑戦してみてください！

## 参考リンク

- [pydub公式ドキュメント](https://github.com/jiaaro/pydub)
- [音楽著作権の基礎知識](https://www.jasrac.or.jp/copyright/index.html)
- [サンプリングの歴史と影響](https://www.rollingstone.com/music/music-features/the-history-of-the-sample-in-5-songs-706692/)
Windows PowerShell でショートカットのプロパティを書き換える

## 備忘録的記事
仕事とプライベートでChromeのプロファイルを一発で切り替えたい……
が、情報を取得する記事はまあまああるが、ぱっと見で書き換えるという記事が見つからなかったので備忘録的に残しておくことにする

## コード
```posh
filter ShortcutProperty($properties)
{
    $shell  = new-object -comobject WScript.Shell
    if($properties){
        $shortcut = $shell.CreateShortcut($_)
        $property_names = "Arguments","Description","HotKey","IconLocation","RelativePath","TargetPath","WindowStyle","WorkingDirectory"
        foreach($property_name in $property_names)
        {
            if ($shortcut.$property_name -ne $properties.$property_name)
            {
                Write-Output("Changed Properties`n{0,-16}: {1,-10}   >>   {2, -10}" -f $($property_name), $($shortcut.$property_name), $($properties.$property_name))
            }
            $shortcut.$property_name = $properties.$property_name
        }
        echo ""
        $shortcut.Save()
    }else{
        return $shell.CreateShortcut($_)
    }
}
```

### 使用法

```posh
# プロパティを取得
$f = dir -r -include "Google Chrome*.lnk" | ShortcutProperty

# プロパティを書き換える
$f.Arguments = '--profile-directory="Default"'

# 書き換えたプロパティを使ってショートカットを上書き
dir -r -include "Google Chrome*.lnk" | ShortcutProperty($f)
```

パイプでファイルを渡す

引数付きで実行した場合は書き換え、引数無しで実行した場合はプロパティ情報の出力になる

出力の時は以下のようなフォーマットになる
```
FullName         : path\to\folder\Google Chrome ベータ版.lnk
Arguments        : --profile-directory="Default"
Description      : インターネットにアクセス
Hotkey           : 
IconLocation     : path\to\icon\chrome.exe,9
RelativePath     : 
TargetPath       : path\to\target\chrome.exe
WindowStyle      : 1
WorkingDirectory : path\to\wd\
```

### 参考

https://qiita.com/ShortArrow/items/4efcb80e4cd7eea8e598

https://qiita.com/z0189/items/e661185477888e6e0025

https://stackoverflow.com/questions/9701840/how-to-create-a-shortcut-using-powershell
[DBMS] ロールバックとロールフォワードについて

# ロールバック
障害発生時点からチェックポイントまで、時間を遡ってログファイルを確認し、更新**前**ログを用いてundo※1する。

※1：COMMIT済以外のトランザクションの更新を、ログに記録された更新**前**の値（更新前情報、ログ）を用いてもとに戻す方法

# ロールフォワード
チェックポイントからCOMMIT済のトランザクションまで、時間に沿ってログファイルを確認してし、更新**後**ログを用いてredo※2する。

※2：COMMIT済のトランザクションによる更新を、ログに記録された更新**後**の値（更新後情報、ログ）を用いてもとに更新する方法

# 一覧
|障害|処理||
|:--|:--|:--|
|トランザクション障害|ロールバック|①更新**前**ログでトランザクション前に戻す|
|媒体障害|ロールフォワード|①バックアップファイルでバックアップ時点に戻す<br>②更新**後**ログでトランザクションを適用する|

# 例1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/74b83640-07f6-e866-d122-21c5d4fa61e2.png)


### T1
チェックポイント前にCOMMIT済のため、リスタート不要。
### T2
チェックポイントから障害発生時点の間に、COMMIT済のためロールフォワードによってリスタート。
### T3
障害発生時にトランザクション実行中のため、ロールバックによってリスタート。
しかし、データベースへの書込み処理がないため、更新前後のデータを色くしたログ（ジャーナルファイル）が生成されないため、ロールバック対象外。
### T4
障害発生時にトランザクション実行中のため、ロールバックによってリスタート。
しかし、データベースへの書込み処理がないため、更新前後のデータを色くしたログ（ジャーナルファイル）が生成されないため、ロールバック対象外。
### T5
チェックポイントから障害発生時点の間に、COMMIT済のためロールフォワードによってリスタート。
### T6
障害発生時にトランザクション実行中のため、ロールバックによってリスタート。

# 参考リンク
- [DBMSの障害回復_平成28年秋問30](https://www.ap-siken.com/kakomon/28_aki/q30.html)
- [undo/redo方式_令和４年春問29](https://www.ap-siken.com/kakomon/04_haru/q29.html)
- [前進復帰可能なトランザクション_平成29年秋問30](https://www.ap-siken.com/kakomon/27_aki/q30.html)
- [データベースの障害回復_令和3秋27](https://www.ap-siken.com/kakomon/21_aki/q32.html)
[Dify]ファインチューニングしたモデルをDifyで使ってみよう！


## はじめに
最近はRAFTや、Adaptive-RAGのようなチューニングされたモデルを使う手法が多く出てきています。
そのような手法などは今後もたくさん出てくると思いますし、個人的には、自前でチューニングしたモデルをつかうことは一部の界隈(あいまい)では主流になると思っています。
今回はDifyでもファインチューニングしたモデルを使うにはどうすればいいか？に関して書きます。

基本的な流れは
**ファインチューニング → GGUFに変換 → Ollamaで動くようにする → Difyで動くようにする。**
です。

ではいきましょう。
## ファインチューニング

ファインチューニングに関してはこちらの記事を読んでファインチューニングしてください。
すでに使いたいモデルがある人は次に進んでください。

https://qiita.com/hudebakononaka/items/0375c334ed26a6f49f68


## ファインチューニングしたモデルをGGUFに変換しよう。

ファインチューニングしたやつをGGUFに変換して使用します。
GGUF変換はこちらの記事に沿ってやってみてください。
すでに使いたいモデルのGGUF形式を持っている人は次に進んでください。

https://qiita.com/hudebakononaka/items/ca295eae60231d7d025f

## ファインチューニングしたモデルをOllamaで動くようにしよう！

```sh
mkdir ollama_model
```
GGUF形式をHuggingFaceからダウンロードしollama_modelに格納しておきます。
そしてollama_modelでModelfileを作成します。中身は以下です。
```:Modelfile
FROM ./your_model.gguf
```

そしてOllamaでモデルを使えるようにします。

```
ollama create your_model_name -f Modelfile
```

これでOllamaでファインチューニングしたモデルが使えるようになります。

## OllamaをDifyと連携しよう！

Difyとの連携を書いた記事があるのでそちらを参照してください。

https://qiita.com/hudebakononaka/items/d33179f2e72030cfd184

今回は以下のような設定になります。
![スクリーンショット 2024-07-14 16.50.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376115/ada5f258-d1a7-6b7b-d872-ed29dc87e2b1.png)


## Difyを動かしてみよう

最後に実際に動くか確認してみましょう。
![スクリーンショット 2024-07-14 16.54.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376115/2f13cae0-e9ef-f6ae-f644-1053113eeeee.png)

動きはしますね。ただファインチューニングしたLLMから出力される内容が変ですね...

## 最後に

Xやってるので気になる方はフォローお願いします。

https://x.com/hudebakonosoto