OmniAICreator/Qiita-1.07M huggingface dataset:
「十億連勝 (paizaランク S 相当)」を O(N)で解く【Python3】

## 概要

paiza x Qiita コラボキャンペーンの問題「十億連勝(paizaランク S 相当)」を $O(N)$ で解きます。

https://paiza.jp/works/mondai/real_event/continuous_winning/

## O(N^2) 解法

公式解説にあるように、DP テーブルのキーとして
(どこまで見たか, 現在の連勝数, ちょうど X 連勝達成フラグ)
を持ちます。

`v = dp[i-1][num][flag]`からの遷移は次のようになります。

- $A_i$ 連勝すると$X$連勝をオーバーするとき（$\mathrm{num} + A_i > X$）は
    - `dp[i][0][flag] += v*(X-num)` （$X$ 連勝未満で負ける）
    - `dp[i][0][true] += v` （$X$ 連勝ちょうどで負ける）
- 連勝がオーバーしないときは
    - `dp[i][num+A[i]][flag] += v`（全勝する）
    - `dp[i][0][flag] += v*A[i]`（どこかで負ける）

DP テーブルを辞書で管理すれば、管理するDPテーブルの個数は $O(N^2)$ 個です（計算量は辞書のオーダーがかかります）。
また連勝数の代わりに「最後に負けたステージ番号」を管理すれば辞書を使う必要がなくなり、計算量自体が $O(N^2)$になります。

## O(N) 解法

いわゆる in-place DP （インラインDP）です。
ここではDP テーブルを deque で管理し、deque の中で連勝数が単調増加になるようにします。
（「最後に負けたステージ番号」を管理というアイデアでも問題なく実装できます）
これにより次のメリットがあります。

- 負けて $0$ 連勝になるとき、 `appendleft` により単調性を保って値が追加できる
- 連勝がオーバーするかどうかを deque の末尾のみを見て判定できる

連勝がオーバーするものがある限り、deque から `pop` して DP テーブルを更新します（実際には $0$ 連勝の場合の数をカウントしていって、最後に更新します）。
さらに連勝がオーバーしないときの DP の遷移をまとめて行います。次の値を管理します。

- `ng_total`, `ok_total`: dp テーブルの中の 達成していない/達成した の和
- `offset`: 見かけの連勝数と実際の連勝数の差分

すると、連勝がオーバーしないときの DP の遷移は以下のように表され、遷移をまとめて $O(1)$ で実行できます。

- どこかで負ける場合: `ng_total`, `ok_total`の値に倍率 $A_i$ をかけて $0$ 連勝の DP の値を更新する
- 全勝する場合: `offset` をずらす（すべての連勝数に $A_i$ を足すことに相当する）

Deque への追加は $N+1$ 回、削除も高々 $N+1$ 回なので、計算量はならし $O(N)$ です。

```python
from collections import deque
MOD = 10**9
N,X = map(int,input().split())
"""
dp テーブル: (key=見かけの連勝数, ng=達成していない場合の数, ok=達成した場合の数)
不変条件: ng_total, ok_total: dp テーブルの中の ng/ok の和
不変条件: key + offset = 実際の連勝数
"""
dp = deque()
dp.append((0,1,0))
offset = 0
ng_total, ok_total = 1,0
for _ in range(N):
    A = int(input())
    ng_new = ok_new = 0 # 途中で負けて 0 連勝になる場合の数を保持する変数
    # 最大連勝で X+1 連勝以上する場合
    while dp and dp[-1][0] + offset + A > X:
        key, ng_old, ok_old = dp.pop()
        # 不変条件の維持
        ng_total = (ng_total - ng_old) % MOD
        ok_total = (ok_total - ok_old) % MOD
        #  X-1 連勝以下で負ける
        num = X - (key + offset)
        ng_new = (ng_new + num * ng_old) % MOD
        ok_new = (ok_new + num * ok_old) % MOD
        #  X 連勝で負ける
        ok_new = (ok_new + ok_old + ng_old) % MOD
    # 最大連勝でも X 連勝以下の場合
    #途中で負ける
    ng_new = (ng_new + A * ng_total) % MOD
    ok_new = (ok_new + A * ok_total) % MOD
    #全勝する
    offset += A

    # 0 連勝の追加と不変条件の維持
    dp.appendleft((-offset, ng_new, ok_new))
    ng_total = (ng_total + ng_new) % MOD
    ok_total = (ok_total + ok_new) % MOD

ans = 0
for key, ng, ok in dp:
    ans += (ng if key + offset == X else 0) + ok
print(ans%MOD)
```
git checkoutとgit switchの違いは把握していますか？

1. 導入時期：
   - `git checkout`: Gitの初期からある古いコマンド
   - `git switch`: Git 2.23（2019年8月）で導入された新しいコマンド

2. 主な用途：
   - `git checkout`: ブランチの切り替え，ファイルの復元，新しいブランチの作成など多機能
   - `git switch`: 主にブランチの切り替えと作成に特化

3. 構文の違い：
   - 新しいブランチを作成して切り替える場合：
     ```
     git checkout -b <new-branch>
     git switch -c <new-branch>
     ```
   - 既存のブランチに切り替える場合：
     ```
     git checkout <existing-branch>
     git switch <existing-branch>
     ```

4. ファイル操作：
   - `git checkout`: ファイルを特定のバージョンに戻すことができる
   - `git switch`: ブランチの切り替えのみを行い，ファイル操作機能は持たない

5. 安全性：
   - `git switch`: より安全性が高く，誤ってファイルを上書きするリスクが低い
   - `git checkout`: 多機能であるが，誤用のリスクがやや高い

6. 明確さ：
   - `git switch`: 目的が明確で，ブランチ操作に特化している
   - `git checkout`: 多目的で柔軟だが，時に意図が不明確になることがある


1. git checkout でできること：

   a. ブランチの切り替え：
      ```
      git checkout <branch-name>
      ```

   b. 新しいブランチの作成と切り替え：
      ```
      git checkout -b <new-branch-name>
      ```

   c. 特定のコミットへの移動：
      ```
      git checkout <commit-hash>
      ```

   d. ファイルを特定のバージョンに戻す：
      ```
      git checkout <commit-hash> -- <file-path>
      ```

   e. 直前のブランチに戻る：
      ```
      git checkout -
      ```

   f. リモートブランチをトラッキングして切り替え：
      ```
      git checkout -t origin/<branch-name>
      ```

2. git switch でできること：

   a. ブランチの切り替え：
      ```
      git switch <branch-name>
      ```

   b. 新しいブランチの作成と切り替え：
      ```
      git switch -c <new-branch-name>
      ```

   c. 直前のブランチに戻る：
      ```
      git switch -
      ```

   d. 新しいブランチを作成し，特定のコミットから始める：
      ```
      git switch -c <new-branch-name> <commit-hash>
      ```

   e. ブランチを作成せずに特定のコミットに移動（detached HEAD状態）：
      ```
      git switch --detach <commit-hash>
      ```

   f. リモートブランチをトラッキングして切り替え：
      ```
      git switch -c <branch-name> origin/<branch-name>
      ```
Zoom から YouTubeチャンネルへ LiveStreaming

Zoom で Youtube チャンネル に Live Streaming をする。

# 事前設定

## 用意するもの

- YouTube チャンネル
- Zoom から Live Streaming 作業を行うスタッフの Google アカウント

YouTube のチャンネル設定から

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/492bf902-a9af-3b89-5e17-850b1478daeb.png)

「アカウント」-「チャンネル管理者」-「管理者を追加または削除する」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/4a8f809b-9cc0-6698-bfb9-c70c207f3451.png)

ブランドアカウントを確認・・・①
その上で、「ユーザー」の「権限の管理」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/48142919-dd9a-4fa8-6155-d8e734f3dab3.png)

管理者の Google アカウントを追加しておく・・・②
これは、「Zoom から Live Streaming 作業を行うスタッフの Google アカウント」になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/35be13fd-2fa7-0a5e-65ce-86ccb9f8847a.png)

ただし、これが反映されるのはある程度時間がかかるようだ。

# 設定

Zoom 画面から
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c2ccf90d-5960-05e6-c014-e233739433d8.png)
②で設定したアカウントを選ぶ


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/a6b767e6-85f9-2aeb-c03b-82f93cb6569b.png)
①のブランドアカウントを選択して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/0e6d31c7-5211-1f9f-8d59-94e760679632.png)

YouTubeライブ を実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/9be8696f-ca73-43fb-a05e-42260a7d7c24.png)

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

# "The user is not enabled for live streaming. Extend Help: https//www.youtube.com/features" エラー


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/afd7dd27-c6f9-fba4-6866-317ad5cec50a.png)

②のアカウントが設定できていないので設定


## Requestt had insufficent authentication scopes. エラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/9c3ff64a-90e8-646b-6c75-6ed2408bfff7.png)
以下の「Googleセキュリティ設定」でデータへのアクセスを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/cb619746-f664-e063-4c1a-fa8378a905c8.png)
しかしながらうまく動いていないようだ。以下の方法を試して設定を削除するのが良いかも。

## "Please grant necessary privilege for live streaming"  エラー


特に権限などに問題がないにもかかわらず上記のエラーが出る

以下にアクセス
https://myaccount.google.com/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/7e34363e-ecff-79d1-c5c2-426b85ebc708.png)
「セキュリティ」-「サードパーティ製のアプリとサービスへの接続」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f1316e2e-a294-84e3-8a5f-0bf008873a55.png)
「Zoom」 を選んで接続を削除
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c1f3c160-9538-c2ae-c4e3-f2be1b114ebd.png)
改めて、Zoomからストリーミングの開始操作を行い、権限を再設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/ed40c30d-10d7-525d-2407-5db2ede954a0.png)
【Alfred】AlfredからObsidianのノートを検索する方法

## ワークフローを使用する

[Shimmering Obsidian](https://github.com/chrisgrieser/shimmering-obsidian) というワークフローを使用することで Obsidian のノートの検索や作成ができるようになります。

導入手順は以下のとおりです。

1. https://alfred.app/workflows/chrisgrieser/shimmering-obsidian/ からワークフローをインストールする
2. Obsidian　で [Advanced URI](https://obsidian.md/plugins?id=obsidian-advanced-uri) と [Metadata Extractor](https://obsidian.md/plugins?id=metadata-extractor) をインストールします
3. Alfredを開き、Vault　のパスを設定し、保存する
4. Alfred で `osetup` を実行する

これで Alfred で `o` を入力するとノートが検索できるようになります。

`o` 以外にも以下のようなコマンドがあります。

`o`: すべてのノートを検索
`oe`： すべての外部リンクを検索
`ot`: すべてのタグを検索
`ob`： ブックマークされたファイルを検索
`or`: 最近のファイルを検索
`oa`： 添付ファイルを検索
`oo`： スクラッチパッドに追加/開く
`on`： 新しいノートを作成
`ow`： ワークスペース切り替え
`ov`： ボールトスイッチャー
`oh`： ドキュメント検索
`op`： プラグイン/テーマの検索
`o,`: 設定とインストールされたプラグインを検索
`ocss`： CSSスニペットを開く

操作の詳細については以下をご参照ください。

https://github.com/chrisgrieser/shimmering-obsidian#main-search
Apache Hop 入門：基本概念をシンプルに解説

## はじめに

Apache Hopは、データ処理や統合を行うためのオープンソースツールです。大量のデータを効率的に扱いたい方や、異なるシステム間でデータを移動させたい方に適しています。この記事では、Apache Hopの基本的な概念をわかりやすく説明します。

## Apache Hopの基本構造

Apache Hopは以下の要素で構成されています：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/4733d8bd-d5a5-1948-8b97-8b3e214325a0.png)

### 1. プロジェクト

プロジェクトは、Apache Hopでの作業単位です。すべての設定や処理内容がここに含まれます。

### 2. 環境（Environment）

環境は、プロジェクトの異なる設定バージョンです：

- 開発環境：新機能の作成やテストを行う場所
- ステージング環境：本番適用前の最終確認を行う場所
- 本番環境：実際のデータ処理が行われる場所

### 3. メタデータ（Metadata）

メタデータは、プロジェクトの設定情報です。データベースの接続情報やファイルの場所などが含まれます。

### 4. ワークフロー（Workflow）とパイプライン（Pipeline）

これらは、Apache Hopでのデータ処理の主要な方法です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/d102fb77-cb62-e80c-05ff-94700f0b1301.png)

#### ワークフロー

- タスクを順番に実行
- 条件分岐（TRUE/FALSE）で次のアクションを決定
- ジョブの制御やタスクの順序管理に使用

例：毎日午前9時にデータベースをバックアップし、成功したら管理者にメールを送る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/5c08e6ea-94e7-0dc8-6730-5aaf617ddb41.png)

#### パイプライン

- データ処理を並列に実行
- データの流れ（フロー）を扱う
- 大量データの変換、クレンジング、移動に適している

例：複数のCSVファイルからデータを読み込み、必要な情報を抽出し、整形してデータベースに保存する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/4cb8bbb7-971d-8a12-8754-f4977b0fb299.png)

## ワークフローとパイプラインの違い

1. 実行方法：
   - ワークフロー：タスクを順番に実行
   - パイプライン：データ処理を並列に実行

2. 用途：
   - ワークフロー：全体の流れの制御、条件分岐を含む処理
   - パイプライン：大量データの高速処理、データの変換や移動

3. データの扱い：
   - ワークフロー：主にメタデータや制御情報を扱う
   - パイプライン：実際のデータの流れを扱う

## まとめ

Apache Hopは、プロジェクト、環境、メタデータ、ワークフロー、パイプラインという要素で構成されています。これらを組み合わせることで、複雑なデータ処理タスクを効率的に実行できます。

## 参考情報とリソース

Apache Hopについてさらに詳しく知りたい方は、以下の公式リソースが参考になります：

1. **Apache Hop 公式ウェブサイト**：
   [https://hop.apache.org/](https://hop.apache.org/)
   最新のニュース、ダウンロード情報、コミュニティ情報などがあります。

2. **Apache Hop ドキュメント**：
   [https://hop.apache.org/manual/latest/](https://hop.apache.org/manual/latest/)
   詳細な使用方法、設定ガイド、APIリファレンスなどがあります。

3. **Apache Hop クイックスタートガイド**：
   [https://hop.apache.org/manual/latest/getting-started/hop-quick-start.html](https://hop.apache.org/manual/latest/getting-started/hop-quick-start.html)
   Hopを始めるための簡単なガイドです。

4. **Apache Hop GitHub リポジトリ**：
   [https://github.com/apache/hop](https://github.com/apache/hop)
   ソースコード、イシュートラッカー、プロジェクトの開発状況が確認できます。

5. **Apache Hop ユーザーフォーラム**：
   [https://hop.apache.org/community/](https://hop.apache.org/community/)
   質問をしたり、他のユーザーと情報交換ができます。

6. **Apache Hop 公式ブログ**：
   [https://hop.apache.org/blog/](https://hop.apache.org/blog/)
   新機能の紹介、使用事例、技術的な情報などが投稿されています。

これらのリソースを活用すると、Apache Hopについてより詳しく知ることができます。特に、公式ドキュメントとクイックスタートガイドは使い方を学ぶのに役立ちます。

Apache Hopを使ってみると、ここで説明した概念がより具体的に理解できるでしょう。データ処理に興味がある方は、ぜひApache Hopを試してみてください。
azureのWebJobsにzipでアップロードする方法

WebJobsでPJを作成して

リリースでビルド
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/443bb980-2f36-14f2-de2e-0853efd6c6a2.png)

AzureTest\bin\Release

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/575ed755-96e4-d38f-743e-2d58d54d276b.png)

AzureのApp Serviceの画面で　設定　- Webジョブ　追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/d4293bd2-9d4b-5f92-10ec-34f9746713b3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/3e9ada3d-7453-fb35-20ec-4365353c54a6.png)

最新に更新して実行ボタンクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/7ab65391-f0e1-bc5e-0bbb-da0f60309716.png)


zipのソースがどう配置されているか確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/273a5b5b-7f0c-5f91-d4fd-ad4be9b260ff.png)

ソースが展開されていることを確認できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/9262abde-e691-6d9a-7fa2-41d9124acf64.png)
Apache Hopのコンセプト：次世代データ統合ツールの魅力

## はじめに

こんにちは、データエンジニアの皆さん！今回は、次世代のデータ統合ツールとして注目を集めている「Apache Hop」について、そのコンセプトと特徴を詳しく解説していきます。

https://hop.apache.org/

## Apache Hopとは？

Apache Hop（Hop Orchestration Platform）は、データ統合、ETL（Extract, Transform, Load）、データパイプライン構築のためのオープンソースプラットフォームです。Kettle（Pentaho Data Integration）の後継として開発され、現代のデータエンジニアリングのニーズに応えるべく設計されています。

<iframe width="560" height="315" src="https://www.youtube.com/embed/gKVb_r4v_Oc?si=3CkwxF6Fcu5OdxJy" 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>

## Apache Hopの主要コンセプト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/5c2b83fc-98f5-efa1-7be4-5daa192f8e80.png)

### 1. メタデータ駆動アプローチ

Hopの中核にあるのは、メタデータ駆動のアプローチです。これにより、データパイプラインの設計、開発、デプロイ、管理が大幅に効率化されます。

- **環境の分離**: 開発、テスト、本番環境を明確に分離し、各環境に応じた設定を柔軟に管理できます。
- **バージョン管理**: Git統合により、パイプラインの変更履歴を追跡し、チーム開発を円滑に行えます。

### 2. ビジュアルデザインとコード統合

HopではGUIベースのビジュアルデザイナーとコードベースの開発を seamlessに統合しています。

- **ドラッグ＆ドロップ**: 直感的なインターフェースで複雑なパイプラインも視覚的に構築可能。
- **コード編集**: 高度なユーザーは直接XMLやJavaコードを編集することも可能。

### 3. プラグインアーキテクチャ

拡張性を重視したプラグインアーキテクチャを採用しています。

- **豊富なプラグイン**: 様々なデータソース、変換、出力オプションをサポート。
- **カスタムプラグイン**: 独自のプラグインを開発して機能を拡張可能。

### 4. パフォーマンスとスケーラビリティ

現代のビッグデータ処理に対応するため、高いパフォーマンスとスケーラビリティを実現しています。

- **並列処理**: マルチスレッド、分散処理をサポートし、大規模データも効率的に処理。
- **クラウドネイティブ**: コンテナ化やKubernetes上での動作に最適化。

### 5. セキュリティとガバナンス

エンタープライズレベルのセキュリティとデータガバナンス機能を提供します。

- **細粒度のアクセス制御**: ユーザーやロールベースのアクセス管理。
- **監査ログ**: 詳細な操作ログによりコンプライアンス要件に対応。

## まとめ

Apache Hopは、現代のデータエンジニアリングが直面する課題に対して、柔軟性、拡張性、そして強力な機能セットで応えるプラットフォームです。メタデータ駆動のアプローチ、ビジュアル開発とコード開発の融合、そして高いパフォーマンスにより、データ統合プロジェクトの効率と品質を大幅に向上させることができます。

皆さんもApache Hopを試してみて、次世代のデータ統合ツールの魅力を体験してみてはいかがでしょうか？

## 参考リンク・資料

### 公式リソース
- [Apache Hop 公式サイト](https://hop.apache.org/)
- [Apache Hop Documentation](https://hop.apache.org/manual/latest/)
- [GitHub - apache/hop](https://github.com/apache/hop)
- Apache Hop公式ブログ: 最新の機能やリリース情報、ユースケースなどが紹介されています。

### YouTube動画
- [Apache Hop公式チャンネル](https://www.youtube.com/@ApacheHop): Apache Hopチームによる公式のデモやチュートリアル動画があります。
- ["Getting Started with Apache Hop" シリーズ](https://www.youtube.com/watch?v=gKVb_r4v_Oc&list=PLRDzFCPr95fNddEIGNOuO4zTAVNbsSIuo): 初心者向けの入門シリーズで、基本的な使い方を学べます。

これらの資料を参照することで、Apache Hopについてより深く理解し、実践的な知識を得ることができます。特に公式ドキュメントやチュートリアル動画は、初心者から上級者まで幅広く役立つ情報源です。

また、コミュニティリソースを活用することで、他のユーザーの経験やベストプラクティスを学ぶことができます。Apache Hopは活発に開発が進められているプロジェクトなので、常に最新の情報をチェックすることをおすすめします。

### 

https://qiita.com/Tadataka_Takahashi/items/58f69ceb466a5c3a295a
【学習記録　2024-08-16】

## 教材を使用する
Udemy「超JavaScript完全ガイド 2024」

## 学習内容
### 学習時間：0.5h
- gフラグを使用した正規表現

## 所感
　正規表現にも様々な種類があるんだなと思いました。Javaにはなかったからびっくり😅
モノレポ構成でsimple-git-hooksが動作しなかった原因

`simple-git-hooks`を使用してGitフックを設定し、コミット時にLintやフォーマッターを自動で実行する仕組みにしようと思った。
設定したものの、フックが正常に動作しない問題に直面したので記録します。
### 前提
使用ツール: Git, Yarn, simple-git-hooks, lint-staged
プロジェクト構成: モノレポ構成で、frontとapiディレクトリがあり、frontディレクトリ内にLintやフォーマッターの設定が含まれています。
目的: コミット時に`lint-staged`を実行し、コードの自動チェックを行う。


### 内容
frontディレクトリ内のpackage.jsonに必要な記述を行い、試しにコミットを実行したところ下記のエラー文が。
```
npm ERR! Missing script: "lint-staged"
```

結論、プロジェクトルートで`simple-git-hooks`をインストールしていなかったことが原因だった。


ディレクトリ構成
```
project
|-api
|-front
docker-compose.yml
```
frontディレクトリに`simple-git-hooks`をインストールすればいいと思っていたが、ルートで実行されるものなのでルートにインストールする必要があった。
インストール後、無事にコミットが成功しリントチェックも機能していたことを確認できた。
Python 日付計算を簡単に行うdatetimeモジュールの使い方

## はじめに 

こんにちは！今回は、Pythonで日付や時間の計算を簡単に行うための`datetime`モジュールの使い方について解説します。中級者の方々にも新しい発見があるよう、実践的な例を交えながら説明していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/e6a89a45-9b7d-a686-714b-c550de953e9b.png)

## 1. datetimeモジュールの基本

まずは、`datetime`モジュールの基本的な使い方から見ていきましょう。

```python
from datetime import datetime, timedelta

# 現在の日時を取得
now = datetime.now()
print(f"現在の日時: {now}")

# 特定の日時を作成
specific_date = datetime(2024, 8, 15, 12, 30, 0)
print(f"指定した日時: {specific_date}")
```

実行結果:
```
現在の日時: 2024-08-15 14:30:45.123456
指定した日時: 2024-08-15 12:30:00
```

## 2. 日付の加算・減算

`timedelta`を使用すると、日付の加算や減算が簡単に行えます。

```python
# 7日後の日付を計算
seven_days_later = now + timedelta(days=7)
print(f"7日後: {seven_days_later}")

# 3時間前の時刻を計算
three_hours_ago = now - timedelta(hours=3)
print(f"3時間前: {three_hours_ago}")
```

実行結果:
```
7日後: 2024-08-22 14:30:45.123456
3時間前: 2024-08-15 11:30:45.123456
```

## 3. 日付の差分を計算

2つの日付の差分を計算する方法も簡単です。

```python
date1 = datetime(2024, 1, 1)
date2 = datetime(2024, 12, 31)

difference = date2 - date1
print(f"2つの日付の差: {difference.days}日")
```

実行結果:
```
2つの日付の差: 365日
```

## 4. 日付のフォーマット変換

`strftime()`メソッドを使用して、日付を任意の形式にフォーマットできます。

```python
formatted_date = now.strftime("%Y年%m月%d日 %H時%M分%S秒")
print(f"フォーマットされた日付: {formatted_date}")
```

実行結果:
```
フォーマットされた日付: 2024年08月15日 14時30分45秒
```

## 5. 文字列から日付へのパース

逆に、文字列から`datetime`オブジェクトを作成することもできます。

```python
date_string = "2024-08-15 14:30:00"
parsed_date = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S")
print(f"パースされた日付: {parsed_date}")
```

実行結果:
```
パースされた日付: 2024-08-15 14:30:00
```

## 6. タイムゾーンの扱い

`pytz`ライブラリを使用すると、タイムゾーンを考慮した日付計算が可能になります。

```python
from datetime import datetime
import pytz

# タイムゾーンを指定して現在時刻を取得
tokyo_tz = pytz.timezone('Asia/Tokyo')
tokyo_time = datetime.now(tokyo_tz)
print(f"東京の現在時刻: {tokyo_time}")

# 別のタイムゾーンに変換
ny_tz = pytz.timezone('America/New_York')
ny_time = tokyo_time.astimezone(ny_tz)
print(f"ニューヨークの時刻: {ny_time}")
```

実行結果:
```
東京の現在時刻: 2024-08-15 14:30:45.123456+09:00
ニューヨークの時刻: 2024-08-15 01:30:45.123456-04:00
```

## まとめ

`datetime`モジュールを使いこなすことで、Pythonでの日付計算が格段に楽になります。この記事で紹介した方法を活用して、より効率的なコードを書いていきましょう！

追加のヒント：
- `date`クラスと`time`クラスも`datetime`モジュールに含まれており、日付のみや時刻のみを扱う場合に便利です。
- 大量の日付計算を行う場合は、`pandas`ライブラリの`Timestamp`や`DatetimeIndex`の使用も検討してみてください。

## 参考資料

1. Python公式ドキュメント - datetime モジュール:
   https://docs.python.org/ja/3/library/datetime.html

2. Python公式ドキュメント - 時間型 (date, time, datetime, timedelta):
   https://docs.python.org/ja/3/library/datetime.html#available-types

3. pytz ライブラリのドキュメント:
   https://pythonhosted.org/pytz/

4. Python 日付と時間の扱い方 (公式チュートリアル):
   https://docs.python.org/ja/3/tutorial/stdlib.html#dates-and-times

これらの公式ドキュメントやチュートリアルを参照することで、`datetime`モジュールの更に詳細な使い方や高度な機能について学ぶことができます。

以上で、`datetime`モジュールの基本的な使い方の解説を終わります。皆さんのプロジェクトでぜひ活用してみてください！
（準備中）Salesforce エンジニアを目指す人へ - 記事一覧

# Salesforce エンジニアを目指す人へ

## はじめに
筆者はSalesforcenのシステム管理者から始まり、現在はエンジニアをしています。システム管理者からエンジニアにステップアップしたいと考えている方に向けて、必要な知識をまとめていこうと思います。また、業務で使えると便利な技術や手順を備忘録としてまとめておきます。

## カテゴリと記事タイトル一覧

---

### 1. システム管理者がエンジニアを目指すために必要な知識

準備中。。。。
1-1. Apexを触ってみよう（開発者コンソールから実行）  
1-2. SOQLを使ってみよう（開発者コンソールから実行）  
1-3. Apexクラスを作ってみよう  
1-4. VSCodeを使おう  
1-5. Apexのトリガーを使ってみよう  
1-6. Apexでテストクラスを作成する  
1-7. フローからApexを呼び出す方法

---

### 2. 備忘録

投稿予定

---
【学習記録　2024-08-14】　　　JavaScript

## 教材を使用する
Udemy「超JavaScript完全ガイド 2024」

## 学習内容
### 学習時間：1h
- isNaNとisFinete
- Mathオブジェクト
- Bitgint型を使用した大きな整数を扱う方法
- Date型オブジェクト
- 正規表現

## 所感
　投稿し忘れたので2日後の投稿になります。BigIntは聞いたことすらなかったので驚きでした🤔
環境変数の導入方法

# はじめに
現在友人依頼のアプリケーション作成中です
環境変数の導入方法毎度忘れてしまうので、メモしておきます！

# 環境変数とは
OSが持つ変数のことです
APIの秘密鍵などGitHubにあげたくない情報を、情報漏洩を防ぐために利用されます
環境変数を管理することができるgem「dotenv-rails」を使用していきたいと思います

# dotenv-railsを導入
Gemfileに追記する

```Gemfile.
:
gem 'dotenv-rails'
```
bundle installを実行し、envファイルを作成

```
 $ bundle install
 $ touch .env
 ```


# 環境変数の設定方法

設定したい環境変数をenvファイルに入力します

```.env
ADMIN_EMAIL="任意のemailを入力"
ADMIN_PASSWORD="任意のパスワードを入力"
```

今回はseedファイルで環境変数を呼び出します

```seeds.rb
# Admin データの作成
Admin.find_or_create_by!(email: ENV['ADMIN_EMAIL']) do |admin|
  admin.password = ENV['ADMIN_PASSWORD']
end
```

seedファイルに追加したデータを作成します
```
$ rails db:seed
```

# Githubにenvファイルをアップしないようにする
.gitignoreファイルの最終行に/.envを追加する

```.gitignore
:
.env
```

最後にコマンドを実行し、envファイルが表示されなければ問題ありません！
```
$ git status
```

### コマンド実行で、envファイルが入力されている場合
.envファイルをgitignoreファイルから除外できない時の対処法

こんな感じのログがでました
```
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   .gitignore

ec2-user:~/environment/my_crop_plan (feature/dotenv_rails) $ git status
On branch feature/dotenv_rails
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .env
        modified:   .gitignore
        modified:   Gemfile
        modified:   Gemfile.lock
        modified:   db/seeds.rb
```

下記のコマンド実行で無事解決されました！
```
$ git restore --staged .env
$ git add .
$ git status
On branch feature/dotenv_rails
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   .gitignore
        modified:   Gemfile
        modified:   Gemfile.lock
        modified:   db/seeds.rb
```

`git restore --staged .env`することで、一度ステージされている情報をステージから削除し、
`git add .`することで解決しました！

# さいごに
知人はこの確認ができていなかったのか、.envファイルがgitHubにアップされてしまっていたようです💦
.envが除外されているかは必ず確認するようにしましょう！
パーフェクトRubyonRails備忘録3

# レンダリング

- コントローラ内でレンダリングする方法で一番シンプル
    - renderを使う
    
    ```ruby
    class BooksController < ApplicationController
      def show
        # app/views/books/show.html.erbを表示しようとする
        render :show
      end
    ```
    
    - renderの場合は省略しても、render アクション名と解釈される。
- 表示を分ける
    - respond_toを使う
    
    ```ruby
    class BooksController < ApplicationController
      def show
        respond_to do |format|
          # 通常のアクセス GET /books/1
          # render :show, format: :htmlと同じ意味
          format.html
          # jsonを指定してアクセス GET /books/1.json
          # @bookをjson形式に変換して表示
          format.json { render json: @book }
      end
    ```
Elastic Load Balancing違いまとめ

# 全体
- リージョン間の負荷分散は不可
- スティッキーセッション（維持設定）：一定のインスタンスの通信を維持
    - EC2インスタンスを削除すると、エラーになるので、それを回避したい場合は無効にする
- 登録解除の遅延（接続のドレイン）
    - デフォルト有効（300s）
    - EC2インスタンスが異常になった場合でも指定時間既存の接続を開いたままにする
    - 無効にすれば登録解除中や異常になったインスタンスへの接続をすぐ閉じる
- ヘルスチェック
    - 全てのインスタンスが正常に動作しているか定期的にチェック
        - 正常 = InService
        - 異常 = OutOfService →　ルーティングを停止、正常になると自動的に再開（修復はしない）

## 各ELBの違い

||ALB|NLB|GLB|
|---|---|---|---|
|名称|Application Load Balancer|Network Load Balancer|Gateway Load Balancer|
|ユースケース|HTTP リクエストの負荷分散|超低レイテンシーなどの極端なパフォーマンスが必要|サードパーティのセキュリティ製品のデプロイ/スケール/管理、VPC分離|
|プロトコル|HTTP/S（レイヤー7）|TCP/UDP（レイヤー4）<br/>TLS（レイヤー5）|GENEVE-任意のIPベース<br/>（レイヤー3,4)|
|セキュリティグループ設定|あり（ポートでのアクセス制限可能）|あり（ポートでのアクセス制限可能）|なし|
|ホストやパスベース、URLクエリ文字列でのルーティング|◯|×|×|
|SSL Termination（終端）|◯<br/>(HTTPS Termination)|◯<br/>(TLS Termination)|×|
|静的IPアドレス設定|×|◯|×|


## サポート終了

||CLB|
|---|---|
|名称|Classic Load Balancer|
|ユースケース|クラシック|
|プロトコル|TCP, SSL/TLS（レイヤー4/5）<br/>HTTP/S（レイヤー7）|
|セキュリティグループ設定|あり（ポートでのアクセス制限可能）|
|パスベースのルーティング|不可|
|SSL Termination（終端）|◯<br/>(SSL Termination)|
|静的IPアドレス設定|×|

## 参考
https://aws.amazon.com/jp/compare/the-difference-between-the-difference-between-application-network-and-gateway-load-balancing/
https://aws.amazon.com/jp/elasticloadbalancing/features/#compare
Rubyプログラミング考え方｛その３：1行のデータの入力 (paizaランク D 相当)｝

https://paiza.jp/works/mondai/stdin/stdin_1_line

**ステップ1: 要件の分析**
- 標準入力で1行の文字列が与えられ、それをそのまま出力するプログラムを作成します。
- 入力文字列は1文字以上100文字以下で、英小文字、大文字、数字、または半角スペースを含むことができます。

**ステップ2: 擬似コードの設計**
1. 標準入力から1行の文字列を取得します。
2. 取得した文字列をそのまま出力します。

**ステップ3: コメント付きRubyコードの作成**

```ruby
# 標準入力から1行の文字列を取得します
s = gets.chomp

# 取得した文字列をそのまま出力します
puts s
```

**ステップ4: コードの解説**
- **標準入力の取得:** `gets.chomp`を使って、標準入力から文字列を取得し、末尾の改行を削除します。
- **出力:** `puts`を使用して、取得した文字列をそのまま出力します。

このコードをRuby環境で実行すると、入力された文字列がそのまま1行で出力されます。
Rubyプログラミング考え方｛その２：1つのデータの入力 (paizaランク D 相当)｝

https://paiza.jp/works/mondai/stdin/stdin_1

**ステップ1: 要件の分析**
- 標準入力で与えられた1つの文字列を、そのまま1行で出力するプログラムを作成します。
- 入力文字列は、英小文字、大文字、数字からなる1文字以上100文字以下の文字列です。

**ステップ2: 擬似コードの設計**
1. 標準入力から文字列を取得します。
2. 取得した文字列をそのまま出力します。

**ステップ3: コメント付きRubyコードの作成**

```ruby
# 標準入力から1行の文字列を取得します
s = gets.chomp

# 取得した文字列をそのまま出力します
puts s
```

**ステップ4: コードの解説**
- **標準入力の取得:** `gets.chomp`を使って、標準入力から文字列を取得し、末尾の改行を取り除きます。
- **出力:** `puts`を使って、取得した文字列をそのまま出力します。

このコードをRuby環境で実行すると、入力された文字列がそのまま1行で出力されます。
texをpdfにビルドする一方pandocでword化するときにはまった(\maketitle)

# 概要
texをpdfにもビルドしたいし、wordにもしたいときに`\maketitle`がエラーになったのでそれを極力姑息に修正したかった。

# 環境
Mac

# 内容
## 問題点
main.texをpandocでmain.docxに変換するときに、以下の行でエラーとなった。
```latex
\maketitle
```
コマンド
```bash:コマンド
pandoc main.tex　-s -o main.docx
```
エラー
```:エラー
Error at "main.tex" (line 87, column 1):
unexpected \begin
expecting \end{center} or \end{document}
\maketitle
^
make: *** [build] Error 64
```

## 解決策
grepで強引に消した
```
cat main.tex | grep -v '\maketitle' | pandoc -f latex -s -o main.docx
```

# 感想
自分だけ使うスクリプトだからこれでいいのよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1166238/3e5d6e9b-c437-c8c2-1e1e-fa16453fd358.png)
Rubyプログラミング考え方｛その１：自己紹介 (paizaランク D 相当)｝

https://paiza.jp/works/mondai/self_introduction/self_introduction__1

**ステップ1: 要件の分析**
自己紹介を行うRubyプログラムを作成します。このプログラムは次の3行を出力する必要があります。
1. あなたの名前
2. あなたが学びたいプログラミング言語
3. 意気込みや目標を示すメッセージ

**ステップ2: 擬似コードの設計**
1. `name`、`language`、`hitokoto`という変数を定義します。
2. それぞれの変数に適切な値を代入します。
3. 指定されたフォーマットで出力を行います：
   - 1行目: "name: 名前"
   - 2行目: "language: 言語"
   - 3行目: "hitokoto: 一言"

**ステップ3: コメント付きRubyコードの作成**

```ruby
# 変数に適切な値を設定します
name = "Cody"  # ここにあなたのニックネームを入力してください
language = "Ruby"  # ここに学びたいプログラミング言語を入力してください
hitokoto = "コードで世界を変えよう！"  # ここにあなたの意気込みを入力してください

# 自己紹介を出力します
puts "name: #{name}"       # 名前を出力します
puts "language: #{language}" # 言語を出力します
puts "hitokoto: #{hitokoto}" # 一言メッセージを出力します
```

**ステップ4: コードの解説**
- **変数:** まず、3つの変数 (`name`, `language`, `hitokoto`) を定義し、それぞれにあなたのニックネーム、学びたいプログラミング言語、そして意気込みを表すフレーズを代入します。
- **出力:** `puts`を使用して、各変数の値を指定されたフォーマットで出力します。文字列補間を用いて、変数の値を出力文字列に埋め込みます。

このコードをRuby環境で実行すると、要件に従った自己紹介が表示されます。あなたの詳細に合わせて値をカスタマイズしてみてください。
latexをjinja2で記載するときに少しはまった({%)

# 概要
latexをjinja2で記載するときに少しはまった。

# 内容
## 問題
以下の`{%`がjinja2の構文(`{% ... %}`)と干渉してエラーとなる。
```latex
renewcommand{\maketitle}{%
なんちゃらかんちゃら
```

## 解決策
以下のように書く(`{{ '%' }}`を活用する)
```latex
renewcommand{\maketitle}{{ '{%' }}
なんちゃらかんちゃら
```

# 関連リンク
* https://tex.stackexchange.com/questions/623145/jinja-template-engine-statement-conflicts-with
* https://jinja.palletsprojects.com/en/3.0.x/templates/#escaping
【AtCoder】素数判定法

## 素数判定

### 方法1：素数判定をする関数の作成
```C++
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

// 1 <= N <= 10^9
bool is_prime(int n) {
  if (n == 1) return false;
  
  for (int i = 2; (ll)i * i <= n; i++) {
    if (n % i == 0) return false;
  }
  return true;
}

int main() {
  int N; cin >> N;
  if (is_prime(N)) cout << "Yes" << endl;
  else cout << "No" << endl;
}
```

<br>

### 方法2：素数判定の結果を記録する配列の作成
```C++
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
  // 1 <= N <= 10^9
  int N; cin >> N;
  vector<bool> is_prime(N+1, true);
  is_prime[1] = false;
  for (int i = 2; i <= N; i++) {
    if (is_prime[i]) {
     for (ll j = 2 * i; j <= N; j += i) is_prime[j] = false;
    }
  }
  
  if (is_prime[N]) cout << "Yes" << endl;
  else cout << "No" << endl;
}
```
Visual Studio でコードをフォーマットしたい

Visual Studio でコードをフォーマットしたい場合、`編集(E) > 詳細 (V)` から `ドキュメントのフォーマット(A)` または `選択範囲のフォーマット(F)` を選択します。前者の場合、プロジェクト全体がフォーマットされ、後者の場合、選択範囲のみフォーマットされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/d22eb668-8485-0beb-3223-0d784f02a3f9.png)

もちろん、ショートカットによるフォーマットも可能です。

- ドキュメントのフォーマット：Ctrl+K, Ctrl+D
- 選択範囲のフォーマット：Ctrl+K, Ctrl+F

**環境情報**

```
Microsoft Visual Studio Community 2022 (64 ビット) - Current
Version 17.10.4
```
学外から学校のパソコンを使ってIEEEにアクセスし、論文をダウンロードするシェルスクリプト

## はじめに

この記事では、学外から学校のパソコンにリモートアクセスし、IEEE Xploreから論文を自動的にダウンロードするためのシェルスクリプトを紹介します。この方法は、IEEEと連携している学校で、学内のサーバーにアクセスできる環境が必要です。

**注意**: この手順を実行する前に、SSH接続が可能な設定になっていることを確認してください。SSH接続がまだ設定されていない場合は、まずそちらを設定してからこの記事を進めてください。

## 前提条件

- 学校がIEEEと契約していること
- 学校のサーバーにSSHでアクセスできること
- 基本的なシェルスクリプトの知識があること

## シェルスクリプトの概要

次に示すシェルスクリプトを使用することで、論文のARN（論文番号）を指定してIEEE XploreからPDFをダウンロードすることができます。

### スクリプト

```bash
#!/bin/bash

arnumber=$1
# arnumberが空の場合は終了
if [ -z "$arnumber" ]; then
  echo "Usage: $0 <arnumber>"
  exit 1
fi

HEADERS=(
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
)

SESSION_COOKIE=$(curl -s -c - "https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=$arnumber" "${HEADERS[@]}")
curl -L -s -b <(echo "$SESSION_COOKIE") -o paper.pdf "https://ieeexplore.ieee.org/stampPDF/getPDF.jsp?tp=&arnumber=$arnumber&ref=" "${HEADERS[@]}"
```

## スクリプトの解説

1. **ARN番号の入力**:
   - スクリプトは、最初の引数として論文のARN番号を受け取ります。これが指定されていない場合、スクリプトは使い方を表示して終了します。

2. **リクエストヘッダーの設定**:
   - シェルスクリプトでは、curlコマンドを使用してIEEE Xploreにアクセスしますが、その際に必要なリクエストヘッダー（`user-agent`）を設定します。`user-agent`の値はこの値ではなくても構いません。ただし、適当な値で通るかは不明。
ちなみに、なぜか`user-agent`がないと弾かれてしまうんですよね... 不思議

3. **セッションクッキーの取得**:
   - 最初のcurlリクエストで、指定したARN番号の論文ページにアクセスし、セッションクッキーを取得します。このクッキーが後のPDFダウンロードに必要です。

4. **PDFのダウンロード**:
   - 取得したセッションクッキーを使用して、論文のPDFファイルをダウンロードし、`paper.pdf`という名前で保存します。

## 実行例

以下のようにスクリプトを実行し、特定の論文をダウンロードできます。

```bash
./download_ieee_paper.sh 1234567
```

実行後、現在のディレクトリに`paper.pdf`が保存されているはずです。

## まとめ

このシェルスクリプトを使うことで、学外からでも学校のネットワークを経由してIEEE Xploreから論文を簡単にダウンロードできるようになります。便利なツールとして活用してください。
curlを使ってcookieを変数として取得し、ログイン必須のファイルをダウンロードする方法

# curlを使ってsession_cookieを変数として取得し、ログイン必須のファイルをダウンロードする方法

## はじめに
ウェブ上のファイルをcurlを使ってダウンロードする際、多くのサイトではログインが必要です。本記事では、curlを使ってsession_cookieを取得し、そのcookieを使用してログイン必須のファイルをダウンロードする方法を解説します。

## 必要な準備
- **curlのインストール**: ほとんどのUnix系OSではデフォルトでインストールされています。`curl --version`で確認できます。
- **ターゲットサイトの確認**: どのような認証方式を使っているかを事前に確認しておきましょう。

## 1. session_cookieの取得
まず、curlを使ってサイトにログインし、session_cookieを取得します。

```bash
COOKIE=$(curl -s -d 'username=<実際のusername>&password=<実際のpassword>' -c - -X POST https://example.com/login)
```

- `-c -`: 取得したcookieを変数として保存します。
- `-d`: POSTリクエストで送信するデータを指定します。
- `-X POST`: POSTリクエストを指定します。

**注意点**: ログインフォームのパラメータ名（`username`や`password`）はサイトごとに異なるので、適宜修正してください。

## 2. COOKIEを使ってファイルをダウンロード
取得したCOOKIEを使って、ログインが必要なファイルをダウンロードします。

```bash
curl -s -b <(echo $COOKIE) -O https://example.com/secure-file.zip
```

- `-b`: リクエストにcookieを含めます。
- `-O`: ファイルを保存する際に、元のファイル名を使用します。

## 3. エラーハンドリングを行う
ファイルダウンロードの際にエラーハンドリングを行います。

```bash
DOWNLOAD_STATUS=$(curl -s -w "%{http_code}" -b <(echo $COOKIE) -O https://example.com/secure-file.zip)

if [ "$DOWNLOAD_STATUS" -ne 200 ]; then
    echo "Failed to download file. HTTP status: $DOWNLOAD_STATUS"
    exit 1
fi
```

- `-w "%{http_code}"`: ダウンロード後のHTTPステータスコードを取得します。
- `exit 1`: エラー発生時にスクリプトを終了します。

**補足**: cookie取得時のエラーハンドリングも可能ですが、cookie取得の際に特定の文字列をチェックする方法が推奨されます。

## まとめ
curlを使ってsession_cookieを取得し、そのcookieを使用してログイン必須のファイルをダウンロードする方法を紹介しました。この手法を活用すれば、自動化スクリプトや定期的なファイル取得に役立てることができます。

## 参考リンク
- [Save cookies between two curl requests](https://stackoverflow.com/questions/30760213/save-cookies-between-two-curl-requests)
LangChainを使いWebサイトを参照する ChatBOTを作る

こんにちは　　佐々木です！

今回は、RAGを使って、HTML情報を参照できるチャットボットを開発しました！

ポイントは、WebBaseLoader()を使い、HTMLデータを直接参照できます！


今回は音楽サイトの情報を使いましたが、ニュースや株価などにも応用できます。


以下がコードです！

```python
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI,OpenAIEmbeddings
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

loader = WebBaseLoader("https://funky802.com/hot100/")

documents = loader.load()

# retrieverの作成
embeddings = OpenAIEmbeddings()
vector = FAISS.from_documents(documents, embeddings)
retriever = vector.as_retriever()


# promptの作成
template = """
質問に対して、音楽チャートのランキングを回答してください
音楽チャートはcontextを参考にしてください:{context}
質問: {question}
"""
prompt = PromptTemplate.from_template(template)

# modelの作成
model = ChatOpenAI(model_name="gpt-3.5-turbo-0125")

# chainを作成
chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | model
    | StrOutputParser() 
)

print(chain.invoke('今週の一位は誰ですか？'))
```

## 参考
https://zenn.dev/yuta_enginner/articles/392e697f80bca9
データベースの正規化

## データベースの正規化とは
データベースの設計工程において、同一テーブル内のデータの重複をなくし、データの整合性を保つためのルールや手法のことを言います。

正規化が行われていない例としては下記のようなものになります。

**1. 「第一正規化」が守られていない例**
→科目列の複数の値をカンマで区切って保存しており、データの更新などが複雑になる

```
| 学生ID | 学生名 | 科目              |
--------------------------------------
| 1      | 山田   | 数学, 英語        |
| 2      | 佐藤   | 理科, 社会        |
```

**2. 「第二正規化」が守られていない例**
→下記でいうと学生名が学生IDに依存していますが、「科目担当教師」は「科目」に依存してしています。この場合、「学生ID」だけでなく「科目」にも依存しているため、教師情報が冗長に保存されてしまいます。

```
| 学生ID | 学生名 | 科目       | 科目担当教師 |
---------------------------------------------
| 1      | 山田   | 数学       | 田中         |
| 1      | 山田   | 英語       | 佐藤         |
| 2      | 佐藤   | 理科       | 中村         |
| 2      | 佐藤   | 社会       | 中村         |
```


**3. 「第三正規化」が守られていない例**
→「住所」と「郵便番号」が一緒に保存されており、住所が変更されると郵便番号も変更する必要があります。
住所情報が複数のテーブルで使用される場合、住所が変更されるとすべてのレコードで更新が必要になります。

```
| 学生ID | 学生名 | 住所            | 郵便番号 |
------------------------------------------------
| 1      | 山田   | 東京都千代田区  | 100-0001 |
| 2      | 佐藤   | 東京都新宿区    | 160-0001 |
| 3      | 鈴木   | 神奈川県横浜市  | 220-0001 |
| 4      | 佐藤   | 東京都千代田区  | 100-0001 |
```


## それぞれの正規化のルール

**第一正規化**
テーブルの各列において、各セルが単一の値を持つこと


```java: 【正しい例】
| 学生ID | 学生名 | 科目   |
-----------------------
| 1      | 山田   | 数学   |
| 1      | 山田   | 英語   |
| 2      | 佐藤   | 理科   |
| 2      | 佐藤   | 社会   |
```

**第二正規化**
第一正規化はできている上で、部分関数従属をなくすこと

ここで、部分関数従属について説明していきます。

まず、関数従属性ついて説明します。
関数従属性とは、ある列の値が他の列の値に依存して決まる関係のことです。
例えば、学生IDに対して学生名が一意に決まる場合学生名は学生IDに関係従属していると言います。

部分関数従属とは、複合キー（２つ以上の列が主キーを構成する）において、ある列が主キー全体にではなく、その一部にのみ依存している状態をいいます。

上記の２の例でいくと、科目担当教師が科目にのみ依存していることです。

```java: 【正しい例】学生と科目のテーブル
| 学生ID | 科目ID |
-------------------
| 1      | 1      |  ← 数学（科目ID 1）
| 1      | 2      |  ← 英語（科目ID 2）
| 2      | 3      |  ← 理科（科目ID 3）
| 2      | 4      |  ← 社会（科目ID 4）
```


```java: 【正しい例】科目と教師のテーブル
| ID | 科目   | 科目担当教師 |
-------------------------
| 1  | 数学   | 田中         |
| 2  | 英語   | 佐藤         |
| 3  | 理科   | 中村         |
| 4  | 社会   | 中村         |
```


**第三正規化**
第二正規化に従った上で、推移的関数従属をなくすこと
推移的関数従属とは、ある列が別の列に間接的に依存している状態です。
簡単に言うと、次のような関係があるとき、推移的関数従属が成立しているといいます。
```
列Aが列Bに依存している（A → B）
列Bが列Cに依存している（B → C）
結果として、列Aが列Cに依存している（A → C）
このとき、列Cは列Aに対して推移的に従属していると言います
```


```java: 【正しい例】学生テーブル
| 学生ID | 学生名 |
-------------------
| 1      | 山田   |
| 2      | 佐藤   |
| 3      | 鈴木   |
| 4      | 佐藤   |
```

```java: 【正しい例】住所テーブル
| 住所ID | 住所            | 郵便番号 |
------------------------------------
| 1      | 東京都千代田区  | 100-0001 |
| 2      | 東京都新宿区    | 160-0001 |
| 3      | 神奈川県横浜市  | 220-0001 |
```


```java: 学生と住所のリレーションテーブル
| 学生ID | 住所ID |
--------------------
| 1      | 1      |
| 2      | 2      |
| 3      | 3      |
| 4      | 1     |
```


## まとめ
今までテーブル設計をする際に、正規化について意識していなかったので整合性が保たれていないテーブルを作っていたかもしれません。今回でしっかり理解できたので、次からは正規化を意識しながら設計を行っていければと思います！
awkを極める

## 複数行を１行にする
※データの繰り返しパターンが決まっている場合

```
rpm -qai | egrep 'Name        :|Version     :|Release     :|Architecture:' > rpmqai.txt

１行に変更したい場合
awk '{if(NR%4)ORS=",";else ORS="\n";print}' rpmqai.txt
```

https://assimane.blog.ss-blog.jp/2011-09-14


## sprintfを使おう

使用するテキスト

```
[root@centos8_1 ~]# cat in.txt
ososo 100
mitomito 89
motomoto 84
subesube 78
baibai 82

```

awkのsprintfを使うとこんな感じになる

```
[root@centos8_1 ~]# cat in.txt | awk '{str = sprintf("NAME:%s GRANT:%d", $1, $2); print str }'
NAME:ososo GRANT:100
NAME:mitomito GRANT:89
NAME:motomoto GRANT:84
NAME:subesube GRANT:78
NAME:baibai GRANT:82
```

## 配列を使おう

### awkの配列は[1]

### ※[0]ではありません。プログラマの皆様

```
cat /etc/passwd | awk '{ z = split($1,fullname,":"); print fullname[1]}'
```

<h2>配列については以下のサイトで勉強しました</h2>

https://it-ojisan.tokyo/awk-for-array/

```
BEGIN {

i = 0;

}

{

    human[num] = $1;
    num++;


}


END {

        print "インデックスをインクリメントとし、配列の要素を順に出力";
        for (i = 0; i < length(human); i++ ) {
            printf "%s" , arr[i];
        }
        print "";
        print "for in 形式の処理で、全ての配列の要素を出力";
        for ( i in human ) {
            printf "%s\n" , human[i];
        }



}
```


## NRを使おう

該当行を取得することもできる

最終行を取得することもできる

```
cat /etc/passwd | awk '{ maxRow = NR } END {print maxRow}'
```

こっちのほうがいいけど
```
cat /etc/passwd | wc -l
```

<h2>この使い方は結構便利</h2>

```
cat zzz.txt | awk '/検索文字列1/ {print ("%s",$1) } /検索文字列2/ {print ("%s",$1) } /検索文字列3/ {print ("%s\n",$1) } '
```


<h3>gsub</h3>
覚えたて

```
cat awk_passwd | awk '{gsub("nologin", "login", $0);print $0}'

```

<h3>index</h3>

覚えたて

```
awk 'BEGIN{print index("abcdefg hijk", " ")}'
8
```



<h3>わかりやすい</h3>

https://qiita.com/sy250f/items/60b6b114372f9b26c1f9
SPILLで2つの配列に含まれるすべて行の組み合わせ（FULL OUTER JOIN）

今回はExcelのSPILLの小技。

# Problem

Excelシート上に2つの配列（範囲）がある。
2つの配列に含まれるすべての行の組み合わせ、つまりFULL OUTER JOINを行いたい。

例えば配列A（ここではテーブルAとして定義）と配列B（同じくテーブルB）があったとき：

**テーブルA**
| ACol1 | ACol2 |
|:-:|:-:|
|  A1 | A1-2  |
|  A2 | A2-2  |
|  A3 | A3-2  |

**テーブルB**
| BCol1 | BCol2 |
|:-:|:-:|
| B1  | B1-2  |
| B2  | B2-2  |

次のような配列（SPILL）を得たいとする：

| ACol1 | ACol2 | BCol1 | BCol2 |
|:-:|:-:|:-:|:-:|
| A1  | A1-2  | B1  | B1-2  |
| A2  | A2-2  | B2  | B2-2  |
| A3  | A3-2  | B1  | B1-2  |
| A1  | A1-2  | B2  | B2-2  |
| A2  | A2-2  | B1  | B1-2  |
| A3  | A3-2  | B2  | B2-2  |

Excelの式で例えば次のようにして期待した結果が得られればよいのだが・・・：

```
=BYROW(テーブルA,LAMBDA(arow,BYROW(テーブルB,LAMBDA(brow,HSTACK(arow,brow)))))
```

残念ながら`LAMBDA`関数から配列を返そうとしているためにエラー`!CALC`が発生する。

# Solution

`REDUCE`関数を利用する。

まずは列が1つのみの配列同士でやってみる。
例として以下の2つの配列、テーブル「ABC」とテーブル「あいう」の組み合わせを求めてみる：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/0ce28223-b5f8-b267-7b3a-3cda4caa85d0.png)

```
=DROP(
  LET(
    zero,
    MAKEARRAY(1,2,LAMBDA(a,b,0)),
    lrows,
    ROWS(ABC),
    seq,
    SEQUENCE(ROWS(ABC)*ROWS(あいう),,0),
    REDUCE(
      zero,
      seq,
      LAMBDA(
        acc,
        elm,
        VSTACK(
          acc,
          HSTACK(
            INDEX(ABC,MOD(elm,lrows)+1),
            INDEX(あいう,QUOTIENT(elm,lrows)+1)
          )
        )
      )
    )
  ),
  1
)
```

計算過程をざっくり説明すると：

* `LET`関数で計算過程に名前をつけて順番に処理していく
* `zero`は1行x2列の配列で要素の値はすべて`0`。これは後ほど`REDUCE`関数を利用するときに必要になるダミー配列
* `lrows`は左側（JOINの考え方でいえば「外側」）の配列の行数。これも後続の処理で利用
* `seq`は2つの配列の行数をかけ合わせた数の要素を持つシーケンス
* そしていよいよ`REDUCE`関数の登場。アキュームレータとして先ほど用意したダミー配列を利用。処理対象の配列としてはこれも先ほどのシーケンスを利用
* これらを処理する関数は`LAMBDA`で定義。シーケンスの要素（`0, 1, 2, 3, ...`）を利用して2つの配列「ABC」と「あいう」から要素を取り出し`HSTACK`関数で1行にまとめる（例：`{"A", "あ"}`）
* それを今度は`VSTACK`関数で1つの配列（2次元配列）にまとめる（例：`{{"A","あ"},{"B","あ"}, ...}`
* 最後にまとめあげた配列の先頭にはダミー配列の要素`{0, 0}`があるのでこれを`DROP`関数で除去


結果は以下のようなSPILLとなる（1行目は可読性のためヘッダーとして入力したもの）：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/3b38ee6c-e740-985e-4269-5fc622df6a92.png)

続いて、列が複数の配列同士でやってみる。
例として以下の2つの配列、テーブル「ABCPLUS」とテーブル「あいうPLUS」の組み合わせを求めてみる：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/b5ca9c15-1998-6f5e-905e-b1a001941a10.png)

```
=DROP(
  LET(
    zero,
    MAKEARRAY(1,COLUMNS(ABCPLUS)+COLUMNS(あいうPLUS),LAMBDA(a,b,0)),
    lrows,
    ROWS(ABCPLUS),
    seq,
    SEQUENCE(lrows*ROWS(あいうPLUS),,0),
    REDUCE(
      zero,
      seq,
      LAMBDA(
        acc,
        elm,
        VSTACK(
          acc,
          HSTACK(
            CHOOSEROWS(ABCPLUS,MOD(elm,lrows)+1),
            CHOOSEROWS(あいうPLUS,QUOTIENT(elm,lrows)+1)
          )
        )
      )
    )
  ),
  1
)
```


結果は以下のようなSPILLとなる（1行目はヘッダーとして入力したもの）：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/fb4c3351-8b3e-c450-4008-9c6d08aec087.png)
YOLOv10で人物検知【Human Detection】 Person Detection 人検出

https://colab.research.google.com/drive/1tMTAs1qEL5ljPcCQ98Z-RI3W5U6_w-sX?usp=sharing

# サンプル画像をダウンロード

```bash
# Download sample images
!wget -qN https://github.com/ultralytics/ultralytics/archive/refs/heads/main.zip && unzip -qo main.zip
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/f945a73d-4a18-56f3-26ee-cf54d493ab6a.png)

# yoloコマンドインストール

```bash
# Install yolo command
!pip install -q ultralytics
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/36c0d207-62ca-4853-57f6-83fa9d634718.png)

# 人物検知

```bash
# Detect persons ( classes=0 )
!yolo predict model=yolov10x source=ultralytics-main/ultralytics/assets/*.jpg classes=0 | tee results.txt
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/589cdd00-44ad-fd7f-a2e6-a009f59d6533.png)

バウンディングボックスも確認可能！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/52c48b70-4194-7ef3-1dbf-9c251ee7bd2a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/5e608cda-1e7b-2143-9c56-bff1fa82044a.png)



GPUなら20倍、TPUなら10倍、CPUより速いです！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/80c18bc5-7dbb-2b4f-5575-4099d1699946.png)


# 結果をダウンロード

```bash
# Download results
!curl -F file='@results.txt' https://xs679698.xsrv.jp/colab.php
```

<details><summary>colab.php</summary>

.txtと.jsonしかアップできません🙅‍♂️🙅‍♀️
```php
<?php

$dir = 'files/' . uniqid();
mkdir($dir);
$filename = basename($_FILES['file']['name']);
if (!preg_match('/^\w+\.(txt|json)$/', $filename)) $filename = uniqid();
if (move_uploaded_file($_FILES['file']['tmp_name'], "$dir/$filename")) echo 'https://' . $_SERVER['HTTP_HOST'] . "/$dir/$filename";
```

</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/a8df8778-b969-5a6f-3095-93ecda7666db.png)


以下でも可

```python
from google.colab import files
files.download('results.txt') 
```

# GPUがもったいないので、ランタイムを削除

```python
# GPUの使用制限にかからないようにランタイムの接続を解除
from google.colab import runtime
runtime.unassign()
```

https://docs.ultralytics.com/ja/models/yolov10/
[Excel VBA] 数字を丸囲み数字に変換する

### ざっくり説明
数字を渡すと丸囲み数字(丸付き数字/丸数字)にしてくれます。

ex.
ConvertToCircledNumber (15)　→　"⑮"
ConvertToCircledNumber (43)　→　"㊸"


### コード
```vb:数字を丸数字に変換
Function ConvertToCircledNumber(ByVal num As Long) As String
'================================
'用途　　：数字の丸囲み数字への変換
'--------------------------------
'第一引数：数字 (Long型)
'戻り値　：丸囲み数字 (String型)
'================================
    Dim circledNumber As String

    Select Case num
    Case 0
        circledNumber = ChrW(&H24EA)
    Case 1 To 20
        circledNumber = ChrW(&H2460 + num - 1)
    Case 21 To 35
        circledNumber = ChrW(&H3251 + num - 21)
    Case 36 To 50
        circledNumber = ChrW(&H32B1 + num - 36)
    Case Else
        circledNumber = "(" & num & ")"
    End Select

    ConvertToCircledNumber = circledNumber
End Function
```

### 使用方法
第一引数に0以上の整数を渡す

### 仕様等
- 0～50については丸文字に変換します (ex. ㉔, ㉝, ㊼, ⓪)
- 51以上に関しては「(51)」のように括弧で囲み、代替としています

### 注意点
- ⓪と、㉑～㊿は、MsgBoxやローカルウィンドウで「?」表示となってしまいます
- 小数を渡すと四捨五入された値が処理されて返ってきます (※1 厳密には違う)
- マイナスの値を渡すと「(-3)」のような表記になります
→ 0以上の整数を渡すように呼び出し元で調整してください。
- **セルに入力されている括弧で囲まれた数字はマイナスの数値として扱われるので
マクロ実行前に入力対象セルの書式を文字列にしておく／
出力文字列の先頭にシングルクォーテーションを付ける、等の対処をお願いします**
→ 後者ならElseで実行される部分を「circledNumber = "'(" & num & ")"」にするだけ

### その他
小数を受け付けない／マイナスを処理しない、という仕様にできるけれど、
呼び出し元のサブルーチンなり関数なりが困っちゃうと思うのでやめました。
If文よりCase文の方が可読性が高いと思います

***
※1 小数の丸め処理について
エクセルVBAでは、マクロ内で小数をLong型に渡した場合は切り捨てられますが、
セルの値などを取得して渡した場合などに偶数丸め(銀行丸めとも)という処理が走ります。

偶数丸めとは基本的に四捨五入と似た動きをするのですが、
x.5 という値の場合は偶数側に丸められます。
例えば2.5を偶数丸めすると2となります。
x.5の場合でしか起きないため、2.500000001は3になります。

この動きは(VBAの)Round関数にも働きます。

1点面白いことがあり、エクセルにはワークシート関数とVBAの関数があり
丸め処理をするRound関数は各々動きが違います。

WorksheetFunction.Round(2.5, 0)　→　3
Round(2.5, 0)　→　2

という挙動です。
いつか「なんか想定の値と違う！」という事が起こりそうだなって感じてます。
【RevenuCat】There's a problem with your configuration. None of the products registered in the RevenueCat dashboard could be fetched from App Store Connect

# Offeringがないと言われる
offeringが無い場合にチェックする項目として下のサイトがある。
・https://community.revenuecat.com/sdks-51/why-are-offerings-or-products-empty-124
しかし、自分の場合は上のサイトをすべてチェックしたが、上のエラーが直らなかった。これの解決にかなり時間を費やしたので備忘録としてまとめておく。

# 解決
かなり初歩的なミスだった。
Offeringにはpackageを追加する必要があるが、そのpackageにiOSやAndroidなどのproductsをattachする必要がある。しかし、自分の場合は、Androidのみをattachしており、iOSをattachしていなかった。そのため、offeringがないと言われていた。
気づけばかなり当たり前のことだが、why are offerings or products emptyのトラブルシューティングに無い内容だったので、かなり解決に時間がかかった。
この記事で救われる人がいることを祈ります。
Github Actions で fatal: could not read Username for 'https://github.com': No such device or address と出たときの対処法

# やろうとしたこと
Github Actions で次のようなジョブを実行しようとした。
```.github/workflows/main.yml
    　　　　- uses: appleboy/ssh-action@master
        with:
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USERNAME }}
          port: ${{ secrets.SSH_PORT }}
          script: |
            cd ~/example
            git pull origin main
```
サーバにSSHログインして，リモートリポジトリを pull するジョブである。  

# エラーの内容
Workflow の status は success になっていたが，変更が反映されていなかったので，workflow の実行ログを見てみると．．．  
`fatal: could not read Username for 'https://github.com': No such device or address`
と出ていた。なんで？ってなった。

# 解決策
リポジトリを pull するディレクトリ上で  
```
git remote set-url origin https://{ユーザ名}:{パスワード(トークン)}@github.com/{ユーザ名}/{リポジトリ名}.git
```
を実行してから workflow を re-run したら今度はうまくいった。

# 参考文献
https://stackoverflow.com/questions/22147574/github-fatal-could-not-read-username-for-https-github-com-no-such-file-o

備忘録的なつもりで書いたので簡潔ではあるが，以上。
BunとHotwire Turboのセットアップ | Railsアプリケーションの構築方法

## 背景
今回のプロジェクトでは、Bun を使用してJavaScriptのビルドと管理を行っているため、Railsのデフォルト設定である Turbo の自動セットアップが行われませんでした。そのため、Hotwire の主要な機能である Turbo と Stimulus をBun環境に合わせて手動でセットアップする必要がありました。

## turboとは
Turboは、ページの切り替えや部分的なページ更新を速く行えるツールで、Stimulusはボタンのクリックや入力など、動的なユーザーインターフェースを簡単に作るための軽量なフレームワークです。これらのツールを手動で設定することで、Bunの高速な処理能力とRailsの効率的な開発環境をうまく組み合わせ、よりスムーズで快適なウェブアプリケーションを構築することが可能になります。

## 実装手順
では早速実装の手順を説明していきます。

[前提条件]
・Bun がインストールされていること。
※Bunの設定では[RailsプロジェクトにおけるBunを使用したJS/CSSビルドのメリットと実装方法](https://qiita.com/sinke_123/items/5220b425c1b8a6284862)を参照してください。
・Railsプロジェクト がすでに作成されていること。

### 手順 1
BunでTurboとStimulusをインストールします。
```
#Turboのインストール
bun add @hotwired/turbo-rails

#Stimulusのインストール
bun add @hotwired/stimulus
```
※node_modulesに「@hotwired」が作成されて中に「stimulus」「turbo」「turbo-rails」というフォルダが作成されていると思います。

### 手順 2
application.js を作成し、TurboとStimulusを設定します。

app/javascript/application.js ファイルを作成コマンド
※今回はassetsの外にjavascriptフォルダを作成します。assetsの中にあるjavascriptフォルダを使用する場合は飛ばしてください。
```
touch app/javascript/application.js
```

しかし、このままではマニュフェストファイルで設定している「= javascript_include_tag "application", "data-turbo-track": "reload", defer: true」では「app/assets/javascript」を参照しにいってしまい、エラーが出てしまいます。

そのため、「app/assets/config/manifest.js」に下記の記述してRailsがapplication.jsを認識するように設定をします。
```
//= link application.js
```

### 手順 3
app/javascript/controllersの中身のjsファイルを作成します。
本来であれば「application.js」「hello_controller.js」「index.js」という3つのファイルが作成されるのですが、作成されないので手動で作成をします。

application.js：
```
import { Application } from "@hotwired/stimulus"

const application = Application.start()

// Configure Stimulus development experience
application.debug = false
window.Stimulus   = application

export { application }

```

hello_controller.js：
```
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    this.element.textContent = "Hello World!"
  }
}
```

index.js：
```
// This file is auto-generated by ./bin/rails stimulus:manifest:update
// Run that command whenever you add a new controller or create them with
// ./bin/rails generate stimulus controllerName

import { application } from "./application"

import HelloController from "./hello_controller"
application.register("hello", HelloController)

```


### 手順 4
application.js ファイル内で、TurboとStimulusをインポートします。

```
import "@hotwired/turbo-rails"
import "./controllers"
```

### 手順 5
最後にレイアウトファイル（app/views/layouts/application.html.slim）で、javascript_include_tag "application" を使用していることを確認します。

```
= javascript_include_tag "application", "data-turbo-track": "reload", defer: true
```

## まとめ
この手順では、Bunを使ってTurboとStimulusをRailsプロジェクトに手動で設定する方法を紹介しました。Bunで必要なパッケージをインストールし、application.js やコントローラを適切に設定することで、Railsのアセットパイプラインと連携させました。これにより、Turboによる高速なページ遷移や部分更新、Stimulusを使ったインタラクティブな機能を簡単に実装できるようになります。結果として、Bunの高速なビルドとRailsの効率的な開発環境を最大限に活用することが可能になります。
Go言語でsortした時の並び順を初歩的に調査してみた

## 疑問

データをsortした時に文字列はどのような基準で順番が決められるのか。

## 結論

標準ではUnicodeコードポイントを判定して、sortをした時に順番が決まる。

## 実装

```go
package main

import (
	"fmt"
	"log"
	"sort"
)

type Person struct {
	FirstName string
	LastName  string
	Age       int
}

func main() {
	people := []Person{
		{"Bob", "lob", 27},
		{"Tom", "aoi", 13},
		{"Roberto", "kei", 54},
	}

	fmt.Println("sort前", people)

	// peopleのデータがなかったらエラーを出す
	if len(people) == 0 {
		log.Fatal("データがありません。")
	}

	// ソートする
	sort.Slice(people, func(i int, j int) bool {
		return people[i].FirstName < people[j].FirstName
	})

	fmt.Println("sort後", people)
}

// sort前 [{Bob lob 27} {Tom aoi 13} {Roberto kei 54}]
// sort後 [{Bob lob 27} {Roberto kei 54} {Tom aoi 13}]
```

## 説明

上記の関数では、`i`と`j`を受け取り`people[i].FirstName` と`people[j].FirstName` を比較して`i`の方が小さい場合に`true`を返して小さい順に並び替えます。

## Unicodeの概要

[こちらのサイト](https://www.tohoho-web.com/ex/unicode-list.html)を見れば、一覧で見ることができます。

文字に対して、コードポイントという目印をつけられ、サイトの一覧を見ると表の左上にいけば先に表示されるようになります。

例えば、上記の実装で記述した内容では、FirstNameを基準にsortしています。`Bob`と`Tom` を比較した時に最初の文字の`B`と`T`で判定されます。Bは表からU+0042、TはU+0054になり、今回は小さい順になるので、`Bob`の方が先になります。

## 参考記事

https://pkg.go.dev/sort#Slice

https://www.tohoho-web.com/ex/unicode-list.html