OmniAICreator/Qiita-1.07M huggingface dataset:
Procクラス

# ブロック処理をオブジェクトにする
>`Procクラスはブロックをオブジェクト化するクラス`です。例えば、Stringクラスであれば文字列を、Integerクラスであれば整数を表しますが、Procクラスは`ブロック、つまり「何らかの処理（何らかの手続き)」`を表します。Procクラスのインスタンス(Procオブジェクト)を作成する場合は、次のように`Proc.newにブロックを表します`。
```rb
irb(main):010* hello_proc = Proc.new do # newにブロックを渡している
irb(main):011*   'Hello!'
irb(main):012> end
=> #<Proc:0x0000000111fdf220 (irb):10>
irb(main):013> hello_proc = Proc.new{ 'Hello!' }
=> #<Proc:0x0000000112bb7660 (irb):13>
irb(main):014> hello_proc.call
=> "Hello!"
```
### Procオブジェクトは`call`メソッドを使うことで実行される
```rb
irb(main):015> add_proc = Proc.new{|a,b| a + b}
=> #<Proc:0x000000011296e390 (irb):15>
irb(main):016> add_proc.call(10, 20)
=> 30
```
### デフォルト値をつけることもできる
```rb
irb(main):015> add_proc = Proc.new{|a,b| a + b}
=> #<Proc:0x000000011296e390 (irb):15>
irb(main):016> add_proc.call(10, 20)
=> 30
irb(main):017> add_proc = Proc.new {|a=0, b=0| a+b }
=> #<Proc:0x0000000112a84810 (irb):17>
irb(main):018> add_proc.call
=> 0
irb(main):019> add_proc.call(10)
=> 10
irb(main):020> add_proc.call(10, 20)
=> 30
```
### Kernelモジュールのprocメソッドでも使える
```rb
irb(main):021> add_proc = proc {|a,b| a+b}
=> #<Proc:0x0000000112ff54c0 (irb):21>
...
irb(main):023> add_proc.call(10, 20)
=> 30
irb(main):024> add_proc.call(10)
(irb):21:in `+': nil can't be coerced into Integer (TypeError)
```
https://gihyo.jp/book/2017/978-4-7741-9397-7
オブジェクト指向Cコンパイラ comelangがm5stackで動きました。

と言っても動作確認してませんが、とりあえず、コンパイルは通しました。
だいぶCとの互換性も上がったと思います。
オプションは-m5stackです。単にヘッダーの検索パスを通しているだけですけど。
m5stackのnewlibはcallocがないかもしれないので、動かすのは明日以降。
まあ、comelangは標準Cがあれば、大抵動くと思うので。
PICOでも前書いた通り、動きます。

あとはWAFのcinatoraも実装してます。2時間くらいで実装しました。
まあ、ソース読んでください。使い方は。

```
Cinatora.get().case { (Value === "/") { puts("MAIN PAGE"); } (Value === "/sub_page.html") { puts("SUB PAGE"); } else { puts("UHO!"); } }
```

とかパターンマッチングでサイト作れちゃいます。
SwiftUIのCombineフレームワークについて？

ChatGPTと一緒にCombineフレームワークについて少しだけ学習した記録。今後、理解した部分かｒ追記していければ。

### Combine フレームワークについて

Combine は Apple が提供しているリアクティブプログラミングフレームワークで、データの流れやイベントを非同期で扱います。`Publisher` と `Subscriber` のモデルを使って、イベントの流れを購読（サブスクライブ）し、処理を行うことができます。

- `Publisher`: イベントやデータを生成するもの
- `Subscriber`: イベントを受け取って処理するもの
- `AnyCancellable`: 購読したイベントストリームを後でキャンセルできるトークン

### `AnyCancellable` について

`AnyCancellable` は、Combine の購読をキャンセルするための型です。購読がキャンセルされると、`Publisher` からの更新が停止し、メモリリークを防ぐことができます。

購読を開始したとき、`AnyCancellable` が生成され、これを `Set<AnyCancellable>` のようなコレクションに保持しておくことで、後で購読をキャンセルできます。コレクションに保持しない場合、購読がすぐにキャンセルされてしまいます。

### 使用例

購読を設定し、`cancellables` に保持する例です。

```swift
import Combine

class MyViewModel {
    private var cancellables: Set<AnyCancellable> = []

    func setupSubscription() {
        // Publisherを購読する
        NotificationCenter.default.publisher(for: .someNotification)
            .sink { notification in
                print("Received notification: \(notification)")
            }
            .store(in: &cancellables)  // AnyCancellableを保存
    }
}
```

この例では、通知を購読し、その購読を `cancellables` に保持しています。`store(in:)` メソッドによって、購読はキャンセル可能なセットに保存され、必要に応じてキャンセルできます。

### まとめ

- `cancellables: Set<AnyCancellable>` は、`Combine` フレームワークで使用する購読（`subscription`）のキャンセルを管理するためのプロパティです。
- `AnyCancellable` によって、購読を途中でキャンセルすることが可能になります。
- `Set<AnyCancellable>` は、複数のキャンセル可能な購読を保持しておくために使われます。
AWS クラウドプラクティショナー試験 合格体験記

# AWS クラウドプラクティショナー試験 合格体験記

## はじめに
AWS クラウドプラクティショナー試験（CLF-C02）に合格しました。
この記事では、私の学習方法や使用したツール、勉強期間について共有します。同じ目標を持つ方々の参考になれば幸いです。

---

## プロフィール
- **職種**：ITインフラエンジニア
- **経験**：15年以上
- **IT知識**：基本的なITインフラ知識あり
- **勉強期間**：1カ月半
- **クラウド領域の業務経験**：ほとんど無し

---

## 使用した学習ツール

### 書籍
- **[徹底攻略 AWS認定クラウドプラクティショナー教科書]**
  - 最初に書籍をじっくり読み、AWSの基本的な概念やサービスを理解。
  - 分からない部分はその都度調べて補足しました。

### Udemy
- **【CLF-C02版】これだけでOK! AWS認定クラウドプラクティショナー試験突破講座（豊富な試験問題300問付き）**
  - 動画学習とハンズオンを通じて、実際にAWSを触れる経験を積む。
  - 試験問題が豊富で実践的でした。

### 学習サイト
- **AWS Exam（https://aws-exam.net/clf/）**
  - 試験問題をひたすら解く。
  - 正解率が100%になるまで繰り返しました。

### ChatGPT
- **問題作成と回答**
  - ChatGPTに試験範囲の問題を作成してもらい、自分で回答。
  - 解答に迷った場合は、ChatGPTに解説を依頼することで理解を深めました。

---

## 勉強方法

### 1. 書籍で基礎を固める
まずは書籍をじっくり読みました。AWSのサービスや概念を理解することが目的です。
- 分からないサービスや用語はインターネットで検索しながら進めました。
- 書籍に記載されている模擬問題も積極的に解きました。

### 2. Udemyで実践的に学ぶ
Udemyの講座を購入し、動画とハンズオンで学習を進めました。
- 特に、ハンズオン形式で実際にAWS環境を操作することで、サービスの使い方を体感。
- 動画で試験範囲を網羅的に学べる点が良かったです。

### 3. 問題演習を繰り返す
学習サイト（AWS Exam）でひたすら問題演習を行いました。
- 無料アカウントでは100問まで用意されていますが、
途中で広告が頻繁に入るため、本気で合格を目指すなら有料プランへの登録を強く推奨します。有料プランであれば700問近く用意されています。
- 間違えた問題は正解するまで繰り返し。
- 正解率が100%になるまで徹底的に取り組みました。

### 4. ChatGPTで疑似試験
ChatGPTに問題を作成してもらい、回答しました。
 - プロンプトの例：
> AWSクラウドプラクティショナー試験問題を一問一答形式で出してください。問題数は65問ですべて回答後、成否のサマリと正解率を表示してください。

  上記のように命令すれば実際の試験形式で問題を解くことができます。
  ChatGPTPlusプランに課金している方にはオススメです。
  
---

## 振り返り
1カ月半という短期間での合格は、ツールと効率的な学習計画のおかげです。
- **基礎の理解**を大切にしながら、
- **実践的な演習**を通じて試験の形式に慣れる。

AWSは学ぶべきことが多いですが、正しいリソースと方法を使えば効率的に学習できます。ぜひ参考にしてください！

---

## 最後に
これからクラウドプラクティショナー試験を受ける方々に向けて、一言アドバイスを。

> **「まずは基礎から、そして繰り返し問題演習を！」**

この記事が少しでも役立てば幸いです。ぜひ一緒にAWSの世界を広げていきましょう！
Google apps scriptを使用してLINE messagingAPIのWebhookを使う

公式LINEを利用して飲食店の予約アプリケーションが作りたいと思い立ちました。
有名どころはLステップやエルメ、プロラインフリーといったものもありますが、もっとシンプルなものがあればなぁと思っていました。
事業者が予約機能を導入したいと思っても、飲食に限らずPC・スマホの操作がおぼつかない人もたくさんいらっしゃるので、限定的な機能にしつつ操作がしやすいといったことをベースにして設計していきたいと思います。

LINEを利用するので、LINE Developersの機能としてはmessagingAPIの利用が確定ですが、もしかしたらLINEログインも利用してもいいかも？

## 応答メッセージを送るソースコード
```GAS:lineReservation.gs
const LINE_ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty("LINE_TOKEN");
const LINE_REPLY_ENDPOINT = "https://api.line.me/v2/bot/message/reply"

function doPost(e) {
    var json = JSON.parse(e.postData.contents);
    const replyToken = json.events[0].replyToken;

    const requestMessage = json.events[0].message.text;

    const headers = {
        "Authorization": `Bearer ${LINE_ACCESS_TOKEN}`,
        "Content-Type": "application/json",
    }

    const messages = [{
        "type": "text",
        "text": "受け取った内容：" + requestMessage
    }]

    const option = {
        "headers": headers,
        "method": "POST",
        "payload": JSON.stringify({
            "replyToken": replyToken,
            "messages": messages,
        })
    }

    UrlFetchApp.fetch(LINE_REPLY_ENDPOINT, option);
}
```
上記コードはデプロイして、ウェブアプリのURLをコピーします。
これをLINE Developersのコンソール画面からWebhookのところに貼り付けます。
2024年12月現在、webhookの検証するとランタイムエラーになるのですが、特に問題なくLINE上では応答メッセージが送られてきます。

1. LINEで文章を送信する
1. 公式LINE側にはメッセージイベントが通知されます
1. この時にwebhookで登録したURLへのリクエストが起こる
1. Webhookに登録したウェブアプリとしてのプログラムはdoPost関数（POSTリクエストする関数）を呼び出す

この関数呼び出しでは、メッセージイベントの受信に伴って、リプライトークンの発行も行われており、このトークンに応じて受け取るメッセージも区別することができ、fetchメソッドでAPIをたたくことで応答メッセージの送信をすることが可能になっています。

今回はwebhookによる応答メッセージの送信でしたが、webhookを使わず例えばブロードキャストメッセージやプッシュメッセージの送信といったことが可能です。
単純なメッセージ送信だけならブラウザにボタン用意して、クリックイベントとしてPOSTメソッドを定義、呼び出し

ちなみにGASのdoPost関数実行における`e.postdata.contents`については
> ユーザーがアプリにアクセスするか、プログラムがアプリに HTTP GET リクエストを送信すると、Apps Script は関数 doGet(e) を実行します。プログラムがアプリに HTTP POST リクエストを送信すると、Apps Script は代わりに doPost(e) を実行します。どちらの場合も、e 引数は、任意のリクエスト パラメータに関する情報を含めることができるイベント パラメータを表します。イベント オブジェクトの構造は次の表のとおりです。
と公式のドキュメントに書かれており`e.postdata.contents`はPOST本文のコンテンツテキストを指定しています。

```
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
      "type": "message",
      ～中略～
      "message": {
        "id": "444573844083572737",
        "type": "text",
        "quoteToken": "q3Plxr4AgKd...",
        "text": "@All @example Good Morning!! (love)",
        ～以下略～
      }
    }
  ]
}
```

上記のイベントのようなものが`e.postdata.contents`でとれているので、その`events`の中の0番目の配列のトークンであったり、メッセージの中のテキストが取得されるといった形になります。


とまぁGASでやってみたわけですが、ここからの展開として
- 事業者ごとに管理画面分けたい
- 管理画面分けるためにはログイン機能実装しないといけないからLINEログインも追加で使いたい
- 事業者ごとに店舗は複数あるかもだから店舗の新規追加や編集ができる機能をつけたい
- Googleカレンダーとの連携をしたい

となるとGASではやっぱり厳しくて、バックエンド機能をdjangoで作り、フロントエンド機能をNext.jsで作っていこうと思います。
漸近記法の厳密な定義

## ビッグオー記法

$\mathcal{O}$記法は**漸近的上界**を意味する。

$
\mathcal{O(g(n))} = \{f(n) : ある正定数cとn_0が存在して、すべてのn \ge n_0 に対して0 \le f(n) \le cg(n)を満たす \}
$

## ビッグオメガ記法

$\Omega$記法は**漸近的下界**を意味する。

$
\Omega (g(n)) = \{f(n) : ある正定数cとn_0が存在して、すべてのn \ge n_0 に対して0 \le cg(n) \le f(n)を満たす \}
$

## ビッグシータ記法

$\Theta$記法は**漸近的にタイトな限界**を表現する。

$
\Theta (g(n)) = \{f(n) : ある正定数c_1,c_2,n_0が存在して、すべてのn \ge n_0 に対して0 \le c_1g(n) \le f(n) \le c_2g(n)を満たす \}
$

$\mathcal{O},\Omega,\Theta$記法の定義から以下の定理が成り立つ。

$
任意に選んだ2つの関数をf(n)とg(n)とする。
\\
f(n) = \Theta(g(n))であるための必要十分条件は、
\\
f(n) = \mathcal{O(g(n))}かつ f(n) = \Omega(g(n))
$

## スモールオー記法

$\mathcal{o}$記法は**漸近的にタイトではない上界**を与える。

$
\mathcal{o(g(n))} = \{f(n) : 任意の正定数c > 0 に対して、 ある正定数n_0が存在して、すべてのn \ge n_0 に対して0 \le f(n) \le cg(n)を満たす \}
$

直感的には$n$が増加するに従って、$f(n)$は$g(n)$と比較して無視できるようになる。
つまり、

$
\lim_{n \to \infty} \frac{f(n)}{g(n)} = 0
$

となる。


## スモールオメガ記法

$\omega$記法は**漸近的にタイトでない下界**を与える。

$
\omega (g(n)) = \{f(n) :  任意の正定数c > 0 に対して、ある正定数n_0が存在して、すべてのn \ge n_0 に対して0 \le cg(n) \le f(n)を満たす \}
$

$n$が増加するに従って、$f(n)$は$g(n)$と比較して大きくなるようになる。
つまり、

$
\lim_{n \to \infty} \frac{f(n)}{g(n)} = \infty
$

となる。
「グリーンの公式とグリーンの恒等式の違いを教えて下さい。」をAI先生に教えてもらう。wikipediaだけです。

・深入りをあきらめました。wikipediaだけです。勉強中。申し訳ありません。


**グリーンの公式とグリーンの恒等式の違いを教えて下さい。**　

# ChatGPT先生へ
>グリーンの公式（Green's Theorem）とグリーンの恒等式（Green's Identities）は、いずれも微分積分学の重要な結果であり、特にベクトル解析や偏微分方程式で使われます。ただし、それぞれの目的や内容は異なります。

もしかして、グリーンの定理は、グリーンの公式と同じ？

# Gemini先生へ

# copilot先生へ


# いつもの? sympyの実行環境と 参考のおすすめです。
[(テンプレート)](https://qiita.com/mrrclb48z/items/00dd08b0317069be9342)

# いつもと違うおすすめです。
#### wikipedia

https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AA%E3%83%BC%E3%83%B3%E3%81%AE%E6%81%92%E7%AD%89%E5%BC%8F


#### 過去問
`bash`によってフォルダに次々とアクセスし、ファイル名を変更［備忘録］

```bash
#!/bin/bash

# 親フォルダを指定
parent_dir="A"  # 必要に応じて変更

# figure内のサブフォルダをループ
for subfolder in "$parent_dir"/*; do
  if [ -d "$subfolder" ]; then
    echo "Accessing folder: $subfolder"
    
    # サブフォルダ内の操作例
    # ファイルリストの表示
    ls "$subfolder"
    folder_name=$(basename "$subfolder")
    echo "$folder_name"
    mv "$subfolder/a.png" "$subfolder/a_$folder_name.png" 
  fi
done
```
deploymentのまとめ

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)

# The ActionId specified was invalid for ActionType QuickAction.

+ [Invalid quick action: ServiceContract.Update_Service When trying to validate my package](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ZBctR)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6d511dbc-1cae-a65c-50f3-7f8fb7cae564.png)

:::note
この問題は、親オブジェクトのページ レイアウトの関連リストにクイック アクションを追加するという新しい機能を使用するたびに発生することがわかりました。新しいクイック アクションと、それが追加されたページ レイアウトを一緒にデプロイすると、「無効なクイック アクション: <名前>」というエラーが発生します。これは SF デプロイのバグだと思います。

回避策: 最初にクイック アクションのみをデプロイし、次にクイック アクションが関連リストにあるページ レイアウトを個別にデプロイします。これでうまくいくようです。

同じ問題に遭遇した他のユーザーの役に立つことを願っています。

I found this issue is occurring anytime I use the new-ish feature of adding a Quick Action to a related list on a parent object's page layout.  If I deploy the new quick action and the page layout where it was added together, I get an error of "InvalidInvalid quick action: <name>".  I think this is a bug with SF deployments.

Workaround: First deployed just the quick action and then separately deploy the page layout where the quick action is on a related list; this seems to work.

Hopefully that helps others that encounter this same issue.
:::

+ [what free and secure tools does one use for deployments?](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000KB6Ma)

:::note
すべては、開発者/管理者の数などの具体的な基準によって異なりますが、開発者と管理者のフローと料金ツールを組み合わせたい場合は、Salesforce 独自の DevOps Center を検討する価値があると思います。 

たとえば、無料レベルの Bitbucket や github を使用できます。実際のバージョン管理のほとんどは DevOps Center によって処理されるため、git に関する知識はあまり必要ありません。 

Workbench を使用してデプロイしてみてください。ここでは、コンポーネントをより簡単に取得してデプロイできます。
:::
GitHub Environmentsとは？

# はじめに
GitHub Environmentsというものを使う機会がありそうなので、事前にまとめてみました。

# GitHub Environmentsとは？
主な機能は以下の通りです。
- GitHubのリポジトリごとにデプロイ保護ルールやSecrets・Variablesを設定する。
- GitHub Actionsの実行に承認プロセスを作成し、承認者による承認が実行されるとフローが実行される機能を加える。
- ジョブのトリガー後に、指定時間遅延させる。
- デプロイメントブランチとタグを使用して、環境にデプロイできるブランチとタグを制限する。

https://docs.github.com/ja/actions/managing-workflow-runs-and-deployments/managing-deployments/managing-environments-for-deployment

# 利用条件
Environmentの利用は、リポジトリがパブリックかプライベートか、どのプランを契約しているかで異なります。
|リポジトリの種類|利用可能なGitHubプラン|
|---|---|
|パブリック|すべてのGitHubプラン|
|プライベート|GitHub Pro、GitHub Team または GitHub Enterprise<br>※待機タイマーやレビュー承認機能などの一部の機能はEnterpriseプランのみ利用可能|

# おわりに
今回はGitHub Environmentsについて少し書いてみました。遅延実行や承認フローをプライベートリポジトリで実現したい場合は、Enterprise版の契約が必須となることがわかりました。一方で、パブリックリポジトリだとどのプランでも利用可能のなので、一度試してみたいと思います。
【Python】 matplotlibで任意のエラーバーを追加する方法

二項分布による信頼区間をmatplotlibで図示する際に悩んだので、備忘録として記事にまとめてみました。

matplotlibのerrorbar関数（matplotlib.pyplot.errorbar）を使用しました。

https://matplotlib.org/2.1.2/api/_as_gen/matplotlib.pyplot.errorbar.html


```
fig = plt.figure(figsize=(XX,XX),dpi=XXX)
fig, ax = plt.subplots() 

#（念のため）numericに変換
df["value"] = pd.to_numeric(df["value"])
df["upper"] = pd.to_numeric(df["upper"])
df["lower"] = pd.to_numeric(df["lower"])

# エラーバーの幅（上端・下端）を決める
lower_error = df["value"] - df["lower"]
upper_error = df["upper"] - df["value"]

asymmetric_error = [lower_error, upper_error]

ax.errorbar(np.array(x), np.array(y), xerr=asymmetric_error, fmt='.')
transparent=True

plt.xlim(XX,XX)
plt.xlabel("XXX")
plt.ylabel("XXX")
plt.tick_params(labelsize=XXX)
```
![0-14_total.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397660/2d56d90f-f62f-ec0a-2662-7ef5ef027aea.png)


参考
以下のサイトも参考にさせて頂きました。

https://www.python-beginners.com/entry/20190714/1563079922

https://dreamer-uma.com/errorbar-python/

比率の区間推定（二項分布）は以下のサイトが参考になりました

https://datawokagaku.com/ratio_ci/
タスク管理について（PBIとかSBIとか、、、）

## タスク管理について
今までスクラムやらタスク管理について学んだことなかったので、忘れないように自分用にメモ。

### PBIとは
スクラム開発における「 **プロダクトバックログアイテム（Product Backlog Item** 」のことでビジネス視点から見た時の達成したい目標のこと。例えば「ログイン機能を追加したい」「チャットで自動翻訳できるようにしたい」など。
PMがエンジニアの場合はより専門的な単語で構成されることも多いが、そうでない場合は上記の例のようになるだろう。

### SBIとは
スクラム開発における「 **スプリングバックログアイテム（Product Backlog Item）** 」のことで、PBIを達成するためのタスクのこと指す。
PBIとSBIは、親子関係のように考えるとわかりやすい。
例えば、先ほどの「ログイン機能を追加したい」のSBIには「ログインページの作成」「ログインフォームの作成」「認証機能の作成」などが考えられる。

### スプリントとは
期間のこと。ここでいう期間は開発全体の期間ではなく特定の機能を開発するための期間。オンラインゲームなどでいうシーズンやスプリットに近い定義。スプリントの長さはプロジェクトによって異なるが、通常1〜4週間程度。
先ほどの例だと、下記のように考えられる。
- スプリント1 「ログインページの作成」
- スプリント2 「ログインフォームの作成」
- スプリント3 「認証機能の作成」
let、var

## 背景
再代入されないのに、varを使用。
コンパイルエラーにはならないけど、再代入が必要ないのにvarを使っている点が不適切なので、警告が出た。なので、```let```と```var```を整理
```swift
for _ in 0..<3 {
    var value = Int.random(in: 1...100) // `value`は再代入されない。冗長
    print(value)
}
```

## let
ループごとに新しい定数をつくる
```swift
for _ in 0..<3 {
    let value = Int.random(in: 1...100)
    print(value)
}
```

## var
初期化した変数に対して、ループごとに再代入している
```swift
var value = 0

for _ in 0..<3 {
    value = Int.random(in: 1...100)
    print(value)
}
```
テクニカルライティングについて真面目に考える 1/n

# はじめに

このエントリでは、テクニカルライティングの文章について考えた結果をまとめる。

# テクニカルライティングに求められる文章とはなにか

テクニカルライティングの目的に照らすと、「対象となる読者がスラスラ読めて、誤解の少ないドキュメント」が求められていると言える。では、それは具体的にどのようなものであろうか。
さっき読んだ本の論理的否定をとるとテクニカルライティングの性質の一つを明らかにできると感じたので、付け焼き刃で文章にまとめた。

## 文学的な技巧のない文章

よく、「テクニカルライティングに文学的な技巧は不要」と言われる。では具体的に「文学的な技巧」とは何であろうか。
たまたま読んでいた、三宅香帆さんの入門向け読書術の本にその答えが載っていた。曰く、「わたしたちは普通なら切り捨ててしまうような細部を執拗に書くことに対して「文学」を感じる生き物」である、と。でも、こうも言っている。「小説はぜんぶを書かない」ので、読者は「「なんでこれを書いた・あるいは書かなかったのか？」に気をつけて察する」必要がある、と。なんか矛盾してないか？
無理くり図に整理すると、次のようになる。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602128/9f4b8606-7444-2195-5487-dd71eb495b89.png)

この「三宅文学はさみうちの定理」（私が今名付けた）を性悪に解釈すると、文学というのはどうも読者に対して不親切に振る舞い、十分な情報量を与えないか、ページ数を必要以上に増やすことらしい。
なので、「文学的な技巧のない文章」とは、必要十分な文章量で書く、ということである。こう考えると、テクニカルライティングの許容範囲は狭い。
さらに三宅さんは次のようなことも言っている。
「よい文学作品の文章を丁寧に読んでいくと、本当に、書かれてある言葉にはぜんぶ意味があるのだ」と。
我々はいま、文学の論理的否定を取ろうとしているので、テクニカルライティングでは「丁寧に読まなくても書かれてある言葉には全部意味がある」文章を作る必要がある、といえるだろう。

テクニカルライティングとは必要十分な分量で、丁寧に読まなくても書かれている言葉全部に意味をもっている文章を書くことなのだ。

# 参考文献

三宅香帆(2020), （読んだふりしたけど）ぶっちゃけよく分からん、あの名作小説を面白く読む方法, 笠間書院
変数名にnearとfarを使ってはいけないという話


# 環境と注意事項
今回のエラーは `#include <windows.h>` に由来するものです。linuxユーザーの方は安心してください。
* Visual Studio 2022 (cl.exe 19.41.34120)
* Windows 11

#
先日、c++のコードを書いている時に不可解なコンパイルエラーに遭遇しました。

```c++
float fov, aspect, near, far;
auto m_projection = glm::perspective( fov, aspect, near, far );
```

エラーメッセージはこのようになります。
```
filename.hpp(43): error C2059: 構文エラー: ','
```

少なくとも私の知る範囲では、どこが構文エラーなのか分かりません。そこで試行錯誤の結果、コンパイルが通るよう改変したコードがこちらになります。

```c++
float fov, aspect, near_, far_;
auto m_projection = glm::perspective( fov, aspect, near_, far_ );
```

`near` と `far` は予約語ではなかったはずなのですが、これらのキーワードは使用できないようです。


# 要因
`near`と`far`がプリプロセッサで定義されていたことが要因でした。
先ほどのコードも、`#undef`を挟めば問題なくコンパイルすることができます。
```c++
#undef near
#undef far

float fov, aspect, near, far;
auto m_projection = glm::perspective( fov, aspect, near, far );
```


# 参考文献
こちらの記事のおかげで原因を知ることができました。ありがとうございます。
* [(Qiita) VC++が勝手にキーワードnear, farをマクロ定義している？ ソースをいじらずに回避する離れ業](https://qiita.com/yuba/items/2bea9a8feb65cf5b327b)

# 所感
`windows.h` 難しすぎるだろと思いましたが、C言語からの仕様を受け継ぎながらこう言った挙動を起こさない他の環境が優秀すぎるだけで `windows.h` に落ち度はないのかも...と思いました。
Git SourceTree 操作 個人メモ【Git】

## コミットについて
#### コミットを元に戻す
- `History` の履歴を右クリックして、 `現在のブランチをこのコミットまでリセット` でコミットをリセットする
- Historyのコミットが削除される
- ローカルファイルのファイルは現在の状態のまま変更なし

#### コミットメッセージの修正
- 最後のコミットメッセージのみ修正可能
1. `WORK SPACE` > `ファイルステータス`
2. `現在のブランチをこのコミットまでリセット` にチェック
3. コミットメッセージを編集
4. `コミット` ボタン押下

#### このコミットを打ち消し... について
- 選択したコミットファイルの打ち消しファイルを作成
- 作成後、自動コミットされる
コミットメッセージは ```"Revert {打消しコミット}"```
- 打ち消しファイルが競合する場合、手動マージ・手動コミットが必要
コミットメッセージは ```手入力```

## スタッシュについて
#### 対象ファイル
未コミットのファイル

#### スタッシュ仕様
- 変更ファイルをスタッシュフォルダに保存する
- 新規ファイルはスタッシュフォルダに保存されない（デフォルト）
- ローカルファイルは変更前の状態に戻る

#### オプション
2. `ステージされた変更を残す`
Index にステージしたファイルは変更前の状態に戻さない。
3. `未追跡のファイルを表示`
新規ファイルを保存する。
4. `すべて`
除外ファイル `.gitignore` などすべて保存する。
Cursorプログラミング2日目



# Dockerでのログ保存問題の解決記録

## どんな問題が起きたの？
1. Flaskアプリで入力したデータがログファイルに保存されない
2. Docker上でファイルを保存しようとしたけど、うまくいかない

## なぜ起きたの？
1. **一番大きな理由：コードを更新したのにDockerイメージを作り直してなかった！**
   - アプリのコードを変更しても
   - `docker build`をしないで
   - そのまま古いイメージでコンテナを起動してた

2. **ファイルの保存方法の問題**
   - 最初：一つのファイル(`user_input.log`)を直接つなごうとした
   - 正しい方法：フォルダ全体(`logs/`)をつなぐ

## どうやって解決したの？
1. **まずフォルダを作る**
```bash
mkdir -p logs
touch logs/user_input.log
chmod 666 logs/user_input.log
```

2. **プログラムの書き方を変える**
```python
# ログを'logs'フォルダの中に保存するように変更
with open('logs/user_input.log', 'a') as f:
    # ここでログを書き込む
```

3. **Dockerの手順**
```bash
# 新しくイメージを作り直す
docker build -t flask_docker_app .

# フォルダをつないでコンテナを起動
docker run -d -p 5000:5000 -v "$(pwd)/logs:/app/logs" flask_docker_app
```

## 何を学んだ？
1. **Dockerでの開発手順**
   - コードを変えたら → イメージを作り直す → コンテナを起動
   - この順番が大切！

2. **ファイルの保存方法**
   - 一つのファイルよりフォルダごとつなぐ方が良い
   - ファイルに書き込めるように権限を設定する

3. **問題解決の方法**
   - `docker inspect`でコンテナの中身を確認
   - ログファイルができてるか確認
   - ファイルがちゃんとつながってるか確認

## これからどうする？
1. コードを変えたら必ずイメージを作り直す
2. ログを保存するフォルダは先に計画を立てる
3. 問題が起きたらちゃんと確認する

この経験から、Dockerでアプリを作るときの基本的な手順と、問題が起きたときの対処方法が分かりました！
Azure DatabricksでDatabricks Appsを検証するための環境構築

# はじめに
既にDatabricksを導入しているお客様から、Databricks Appsを既存アプリの移行先として使えないかというご相談があり、
手軽に検証する環境を作るため、Azure Databricksでワークスペースを作り、Databricks Appsを検証できる環境を整備しました。
(自身がDatabricks触ったことないので、いきなりお客さんに環境くださいというのは怖いですね)
(検証のためとはいえ、Databricks自体の契約は自身では現状ないので、Azure社内環境でAzure Databricksを作成するという方針にしました)


# Databricksワークスペース作成
2024/12現在、Azure DatabricksではDatabricks AppsはPubric Previewとなっています。
そのため、Databricks Appsを使用できるリージョンに制限があり、[ここ](https://learn.microsoft.com/en-us/azure/databricks/resources/feature-region-support#serverless-availability)に記載されています。
![Databricks Appsのリージョン制限](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/858bf7a1-e969-d80a-4519-704a8d5fb15e.png)

(2024/12現在使用可能なリージョンは、australiaeast, eastus, eastus2, westeurope, westusのみです)

## ワークスペースの作成
Azure PortalからAzure Databricksを検索し、作成ボタンを押下します。
リージョンはDatabricks Appsが使用可能なリージョンを選択します。(今回はEast USを選択)
価格レベルはPremiumを選んでください。(StandardだとApps作成タイミングでエラーとなります。)
他は適当な値を入力してください。
![Databricksワークスペース作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/befb0a9b-9ea8-84eb-14ab-73c9daa2fe45.png)

そのまま、確認及び作成ボタンを押下し、ワークスペースの作成まで実行します。
デプロイが完了すると、Databricksワークスペースのリソースページに移動します。
作成したワークスペースを開き、"ワークスペースの起動"ボタンを押下します。
![Databricksワークスペース起動](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/977a2021-f290-ec90-77b3-fc0052e693f2.png)

## Databricks Appsの作成
Entra IDのSSOにより自動でワークスペースにログインできます。
![Databricksワークスペースログイン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/2786c236-b4cd-119d-245f-a93d6b95adf6.png)
左のメニューから新規>アプリと遷移すると、Databricks Appsの作成画面に移動可能で、このワークスペースでDatabricks Appsが使用可能であることがわかります。
![Databricks Appsの作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/ba88b7bc-5f4a-eeb5-eda6-7f3d342ce7c3.png)


# まとめ
Azure DatabricksでDatabricks Appsを検証するための環境構築手順を紹介しました。
主なポイントは以下の通りです:

- Databricks Appsは現在Public Previewで、使用可能なリージョンが限定されている
- Azure PortalからDatabricks ワークスペースを作成する際は、Databricks Apps対応リージョンを選択する必要がある

この手順に従うことで、Databricks Appsの検証環境を簡単に構築することができます。


# 参考
- [Databricks Apps とは](https://learn.microsoft.com/ja-jp/azure/databricks/dev-tools/databricks-apps/)
- [サーバーレスの可用性](https://learn.microsoft.com/en-us/azure/databricks/resources/feature-region-support#serverless-availability)
ファイルの最終更新時間をファイル名に追加してコピーする

## 課題
社内システムの夜間処理で**特定のフォルダ**に**特定のファイル名**(日付スタンプを含まない）で自動作成されるデータファイルがある。ファイル名に日付を含まないので、更新されたかどうかはファイルの最終更新時間をチェックする必要がある。更新されたファイルはその日の業務に利用するため、ファイル名に日付をつけて、作業用のフォルダにコピーする。

## 処理
1. **特定のフォルダ**に**特定のファイル名**のファイルがあることを確認する
1. ファイルがない場合はメッセージを表示して処理を終了する
1. ファイルがある場合は以下を行う
    1. ファイルの最終更新時間を確認する
    1. ファイルが２４時間以内に更新されている場合は、ファイル名に日付スタンプを追加して**作業用フォルダ**にコピーする. ただしファイルが既に存在する場合はメッセージを表示して処理を終了する
    1. ファイルが２４時間以内に更新されていない場合は、メッセージを表示して処理を終了する

## 実装

### 事前準備
* VBEの　ツール→参照設定　から"Microsoft Scripting Runtime"を追加する

### コード

```vb
Sub CheckAndCopyFile()

    Dim fso As FileSystemObject
    Dim strPath As String, strDestPath
    Dim f As File
    
    strPath = "C:\Users\user\Desktop\sample\src\data.csv"
    strDestPath = "C:\Users\user\Desktop\sample\dst\data_" & Format(Now, "yyyymmdd") & ".csv"
    
    Set fso = New FileSystemObject
    If Not fso.FileExists(strPath) Then
        MsgBox "File Does Not Exist: " & strPath
        Exit Sub
    End If
    
    Set f = fso.GetFile(strPath)
    If f.DateLastModified > Now - 1 Then
        If fso.FileExists(strDestPath) Then
            MsgBox "File Already Exists: " & strDestPath
            Exit Sub
        End If
        f.Copy strDestPath, False
        MsgBox "Done"
    Else
        MsgBox "File Is Outdated: " & Format(f.DateLastModified, "yyyy-mm-dd hh:mm:ss")
    End If
End Sub
```
cscの作法 その547

# 概要
cscの作法、調べてみた。
xlsxの作成、見つけたので、closedxmlで、やってみた。

# 参考にしたページ

https://qiita.com/iceblue/items/90d6c7f9cde080416e4d

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/058296ce-b728-7205-8d85-b246ca6d823f.png)

# サンプルコード

```

using ClosedXML.Excel;
using System.Data;
using System;
using System.IO;

namespace CreateExcelStream
{
	class Program {
		static void Main(string[] args) {
			var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Booke_s0.xlsx");
			var wb = new XLWorkbook();
			var sheet = wb.Worksheets.Add("Sheet1");
			DataTable table = new DataTable("従業員情報");
			table.Columns.Add("ID", typeof(int));
			table.Columns.Add("名前", typeof(string));
			table.Columns.Add("性別", typeof(string));
			table.Columns.Add("職位", typeof(string));
			table.Columns.Add("部署", typeof(string));
			table.Columns.Add("給与", typeof(decimal));
			table.Columns.Add("入社日", typeof(DateTime));
			table.Rows.Add(1, "佐藤和也", "男", "ソフトウェアエンジニア", "開発部", 750000, DateTime.Parse("2020-03-15"));
			table.Rows.Add(2, "鈴木美咲", "女", "プロジェクトマネージャー", "プロジェクト管理室", 850000, DateTime.Parse("2019-06-22"));
			table.Rows.Add(3, "田中康介", "男", "システムアナリスト", "情報技術部", 800000, DateTime.Parse("2018-07-11"));
			table.Rows.Add(4, "高橋彩香", "女", "UXデザイナー", "デザイン部", 700000, DateTime.Parse("2021-04-05"));
			table.Rows.Add(5, "山本健太", "男", "営業担当", "営業部", 650000, DateTime.Parse("2020-09-10"));
			table.Rows.Add(6, "伊藤真理子", "女", "会計士", "財務部", 720000, DateTime.Parse("2017-11-28"));
			table.Rows.Add(7, "渡辺浩二", "男", "人事マネージャー", "人事部", 820000, DateTime.Parse("2016-05-18"));
			table.Rows.Add(8, "中村菜々子", "女", "法務顧問", "法務部", 900000, DateTime.Parse("2015-02-14"));
			table.Rows.Add(9, "小林翔", "男", "CEO", "最高経営陣", 1200000, DateTime.Parse("2014-08-01"));
			var rangeWithData = sheet.Cell(2, 1).InsertData(table.AsEnumerable());
			sheet.Cell(1, 1).Value = "ID";
			sheet.Cell(1, 2).Value = "名前";
			sheet.Cell(1, 3).Value = "性別";
			sheet.Cell(1, 4).Value = "職位";
			sheet.Cell(1, 5).Value = "部署";
			sheet.Cell(1, 6).Value = "給与";
			sheet.Cell(1, 7).Value = "入社日";
			sheet.Row(1).Style.Fill.BackgroundColor = XLColor.Aqua;
			sheet.Row(1).Style.Font.FontName = "Yu Mincho";
			sheet.Row(1).Style.Font.FontSize = 14;
			sheet.Row(1).Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
			sheet.Row(1).Style.Border.OutsideBorderColor = XLColor.Gray; 
			for (int i = 0; i < table.Rows.Count; i++)
			{
				sheet.Row(i + 2).Style.Fill.BackgroundColor = XLColor.Gray;
				sheet.Row(i + 2).Style.Font.FontName = "Yu Mincho";
				sheet.Row(i + 2).Style.Font.FontSize = 12;
				if ((i + 1) % 2 == 0)
				{
					sheet.Row(i + 2).Style.Fill.BackgroundColor = XLColor.White;
				}
			}
			sheet.Range(2, 1, table.Rows.Count + 1, table.Columns.Count).Style.Border.InsideBorder = XLBorderStyleValues.Thin;
			sheet.Range(2, 1, table.Rows.Count + 1, table.Columns.Count).Style.Border.InsideBorderColor = XLColor.Orange; 
			for (int j = 0; j < table.Columns.Count; j++)
			{
				sheet.Column(j + 1).AdjustToContents();
			}
			wb.SaveAs(filePath);
			Console.WriteLine("ok");
		}
	}
}






```

以上。
ケンプナー関数（Kempner function）

### ケンプナー関数

Wikipediaによると[ケンプナー関数](https://ja.wikipedia.org/wiki/%E3%82%B1%E3%83%B3%E3%83%97%E3%83%8A%E3%83%BC%E9%96%A2%E6%95%B0)とは、

> 階乗 $s!$を$n$が割り切るとき$s$の最小値を与える関数である。例えば、$8$ならば、$ 1!,2!,3!$は8で割り切ることはできないが、$4!$は割り切ることができる。つまり$K(8)=4$である。

### ケンプナー関数を実装する

といっても[OEIS A002034](https://oeis.org/A002034)にコードが紹介されていたのでそのまま使います。アルゴリズムは、

1. まず$n = p_1^{e_1}p_2^{e_2} \cdots p_k^{e_k} (p_iは素数)$のように素因数分解する
1. 各々の素数のべき乗$p_i^{e_i} $に対して$K(p_i^{e_i})$を求める
1. $K(n)=max(K(p_1^{e_1}), K(p_2^{e_2}) \cdots K(p_k^{e_k}))$となる

プログラムは、

```python 
import sympy as sp
def valp(n, p):
    s = 0
    while n: n //= p; s += n
    return s
def K(p, e):
    if e <= p: return e*p
    t = e*(p-1)//p*p
    while valp(t, p) < e: t += p
    return t
def Kempner(N):
  return max(K(p, e) for p, e in sp.factorint(N).items())

N = 12345678
print(f"Kempner({N}) = {Kempner(N)}")
```

（開発環境：Google Colab）

この考え方は以下のProject Eulerの問題を解くのに役に立ちます
* Problem 549: Divisibility of Factorials
* Problem 320: Factorials Divisible by a Huge Integer
「グリーンの定理とグリーンの公式とグリーン関数の違いを教えて下さい。」をAI先生に聞きました。



**「グリーンの恒等式」もありました。３つの比較でなくて「4つの比較」が正しい???ようです。申し訳ありません。**
**Qitta画面の幅がたりないかも。**
**比較の対象が変かも。比較のいい方法をアドバイスいただけると幸いです。**

??? このウィキでページ「グリーンの公式」は見つかりませんでした。...

・先生の回答によって、質問内容を途中で変更しています。
・先生の性格かも。markdown表の行と列の入れ替えについて、
　ChatGPT先生はそのまま
　Gemini 先生は変更されるようです。???サービスかも
 
**グリーンの定理とグリーンの公式とグリーン関数の違いを教えて下さい。**


# Gemini先生へ
>(回答抜粋)
...
例えば、以下のような質問をしていただくと、より詳しい説明が可能です。
「グリーンの定理を使って面積を計算する方法を教えてください。」
「熱伝導方程式のグリーン関数を求める手順を知りたいです。」...


**上記のまとめを、markdownの表形式で出力して下さい。**

| 名称 | 説明 | 主な特徴 |
|---|---|---|
| グリーンの定理 | 閉曲線で囲まれた領域における線積分と重積分を結びつける定理 | 平面上の閉曲線と領域の関係を記述 |
| グリーンの公式 | グリーンの定理の別称 | グリーンの定理と同じ内容を異なる表現で表す |
| グリーン関数 | 特定の偏微分方程式の解 | 偏微分方程式の解法に利用、物理現象の「原因と結果」の関係を表す |

**上記のmarkdown表の、行と列を入れ替えて下さい。**

|  | グリーンの定理 | グリーンの公式 | グリーン関数 |
|---|---|---|---|
| **定義** | 閉曲線で囲まれた領域における線積分と重積分を結びつける定理 | グリーンの定理の別称 | 特定の偏微分方程式の解 |
| **主な特徴** | 平面上の閉曲線と領域の関係を記述 | グリーンの定理と同じ内容を異なる表現で表す | 偏微分方程式の解法に利用、物理現象の「原因と結果」の関係を表す |
| **適用範囲** | 平面上の閉領域 | 平面上の閉領域 | 様々な分野の偏微分方程式 |

**Markdownの表の項目の名称を変更されたのはどうしてですか。**

>(回答抜粋)
>変更の意図...

# ChatGPT先生へ
>(回答抜粋)

**違いのまとめの表 をMarkdwnの表形式で。**
>(回答抜粋)


| 項目          | グリーンの定理         | グリーンの公式         | グリーン関数         |
|---------------|------------------------|------------------------|----------------------|
| **対象**       | 平面の領域             | 空間全体の場           | 微分方程式           |
| **次元**       | 2次元                  | 2次元・3次元           | 一般次元             |
| **役割**       | 面積分と線積分を結びつける | 積分変換               | 微分方程式の解法     |
| **応用分野**   | 流体、面積計算         | 流体、熱、電磁気       | ポテンシャル解析     |

**＞次は私のだそく。(再)**
上記のmarkdown表の、行と列を入れ替えて下さい。

|               | グリーンの定理         | グリーンの公式         | グリーン関数         |
|---------------|------------------------|------------------------|----------------------|
| **対象**       | 平面の領域             | 空間全体の場           | 微分方程式           |
| **次元**       | 2次元                  | 2次元・3次元           | 一般次元             |
| **役割**       | 面積分と線積分を結びつける | 積分変換               | 微分方程式の解法     |
| **応用分野**   | 流体、面積計算         | 流体、熱、電磁気       | ポテンシャル解析     |



# copilot先生へ
未

# いつもの? sympyの実行環境と 参考のおすすめです。
[(テンプレート)](https://qiita.com/mrrclb48z/items/00dd08b0317069be9342) 　開発環境

# いつもと違うおすすめです。
#### Qiita

https://qiita.com/mrrclb48z/items/5ea7ab7b33e05ed31588
ファイルの中身を空にする方法 

ファイルの中身を空にしたい事ありますよね。
例えばログが大量に蓄積されていた時や、デバッグのためにリセットしたりなど。
しかしそんな頻繁に起きるわけでもなく、いざ使うとなっても「なんだっけ？」となり調べていたのでよく使うコマンドの備忘録です。

# 対象
Linux環境 (Mac/WSL/サーバー環境などを想定)
※Windowsユーザーさんはパワーシェルやコマンドプロンプトは対象外ですので注意してください。

# 結論、`truncate -s 0 パス`を使う
```
truncate -s 0 ファイルパス
```
これは既存のファイルの中身を削除して容量を0にする。
注意点としては、ファイルが存在しない場合にはエラーになります。
特段理由がなければこれで問題なくクリアできるのでおすすめです。
`-s`オプションがサイズを指定していて、`0`でファイルサイズを0バイトに指定しています。

# その他の方法
正直調べても色々出てくるので、どれが正解とは言えません。上の`truncate`を使う事で空にするという目的はきちんと果たせているので困ってはないが他にもやり方は色々あるようです。状況に応じて使い分けられると良いかもしれません。

## `echo "" > パス`
これもファイルの中身を空にはしてくれるが、`truncate`とは違い特徴がある。
仕組みとしては、初めに空文字列を出力して、`> (リダイレクト演算子)`を使って右側のパスで指定したファイルに出力するというものみたいです。
注意点としては、 **ファイルが存在しない場合にはファイルを作成する** という事です。
なのでファイルの作成権限がない場合にはエラーがになるかもしれません。

# 余談1：WordPressのログ
以前WordPressの移管作業時にデータが20GBくらいあるサイトに遭遇。
サイト自体も大きい方ではあったので、バックアップデータとか画像なのか？と調べてみることに。
確かに案の定バックアップデータは大きく10GBくらいは削減できました。
それでも10GB、画像がそこまで多くないので調べてみるとログデータが肥大化していました。
たかがログだと侮っていましたが、それでも6GBもありました。
デバッグした後には余計なデバッグログを出力しないように無効化しましょう。

# 余談2: Laravelのログ
Laravelでは`storage/logs/laravel.log`があると思います。
これはLaravel側で必要時には自動で生成されるらしく、`rm`で消しちゃっても問題ないらしいです。
Salesforce API を使ったコールアウト



+ [外部のシステムにコールアウトしてオブジェクトを更新するApexクラスを複数件対応にする](https://qiita.com/Keiji_otsubo/items/b6575aaa41576e52cbfc)
+ [Salesforce API へのゲストユーザーによるコールアウトの外部認証情報](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000J8dxR)

:::note
他にもこの問題に遭遇した人がいる場合は、この記事で解決策を見つけました: https://developer.salesforce.com/blogs/2023/03/using-the-client-credentials-flow-for-easier-api-authentication

実行ユーザーはアプリ ポリシーに保存する必要があり、外部認証情報の ID プロバイダ URL は、デフォルトのドメインhttps://test.salesforce.com/services/oauth2/tokenではなく、直接の組織ドメインである必要があります。
:::
DNS転送

# 近い名前サーバーに転送させる　DNS転送(DNS redirection)
>クライアントを近くのCDNキャッシュ・ノードにマッピングあるいは、転送する最も一般的な方法は、DNS転送を使用することである。その手法を詳しく説明する。クライアントは`https://www.cdn.com/page.html`のURLページを取得しよう。ページ取得のため、ブラウザはDNSプロトコルを用いてブラウザは`cdn.com`の名前サーバーのIPアドレスを知り、それにコンタクトして`www.cdn.com`を解決しようとする。名前サーバーはCDNはより運用されている。それぞれの要求に対して同じIPアドレスを返すのではなく、要求を発したクライアントのIPアドレスを見て、異なる答を出す。答えはクライアントに最も近いCDNノードのIPアドレスである。つまり、シドニーにいるクライアントがCDN名前サーバーに`www.cdn.com`の解決を依頼すれば、名前サーバーはシドニーのCDNノードのIPアドレスを返すが、アムステルダムにいるクライアントが同じ要求を出せば、名前サーバーはアムステルダムのCDNノードのIPアドレスを代わりに返すということである。

### DNS転送させるための考慮すべき要素　距離と負荷で判断する
>CDNノードにマッピングする際に考慮すべき要素は少なくとも二つある。

>第一の要素はネットワーク距離である。クライアントはCDNノードへの距離が短く、大容量のネットワーク経路を持つべきである。そうすると高速なダウンロードが可能になる。CDNはクライアントのIPアドレスをネットワーク上での位置に変換するために、事前に計算した地図を用いる。選択されたCDNノードは文字通り最短経路かもしれないし、そうでないかもしれない。重要なのは、ネットワーク経路の長さとそれに沿った容量制限の組み合わせである。

>第二の要素は、CDNノードがすでに担っている負荷である。CDNノードが過負荷になると、そもそも避けたかった過負荷のWebサーバーと同じように、遅い応答しか得られない。したがって、CDNノード間で負荷を均衡化し、一部のクライアントを少し離れているが負荷の軽いノードにマッピングすることが必要である。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/
jetson でローカルAI環境を構築散財の２０２４を振り返る

## はじめに：2024ローカルAIで何か作ってみたいと思い jetson orin nano購入・・・しかし！！
こんな事を思って、自腹で約90k（９万円）の `jetson orin nano` を購入してローカルAI環境を構築を行おうと思っていた。

しかし、昨日気づいた記事で

https://www.itmedia.co.jp/pcuser/articles/2412/18/news105.html

ここで `菱洋エレクトロ` が出してる価格を見ると「大体半額」の
- 42,460円（税込み）

いやあ「１０月頃に普通に jetson orin nano を９万円ぐらい」で買ったので、いやあ「２０２４年一番のしくじり」と言うか、大失敗しました・・・って感じで昨日そう思った次第です。

前の価格だと、orin nano本体＋SSD+ケース＝１０万円ちょっとで、これと比べると
- ラズパイ5 + MVMEキッド + SSD + ケース＝３万円ぐらい

なので、約３個分以上だったのが、今回の `super` の登場で
- orin nano super + SSD + ケース = ５万円強

なんとラズパイ約２個分の価格差まで縮まったわけで、いやあ本当「大失敗」でしたって話になります。

## 次に：何の因果か 中古のAGX Xavier(32GB)とAGX orin(32GB)も買ってみた
そう言う意味では「中古の jetson orin nano = ６万円ぐらい」だったので、最初からそっちを買っとけば良かったと最初思ったわけですが、中古だと２０２３年発売なのでそれなりに「安くなってる」こともあり、何か業務で購入じゃないから、個人的利用だし「中古」で良かったと、実はこちらでも「しくじり」を「後悔してた」次第です。

そんな感じで「中古のJetsonを色々見てると、稀に安い価格」の「Jetson」があったので、ついポチってしまいました。

- jetson AGX Xavier(32GB): 発売時期：2018年末頃
- jetson AGX orin(32GB): 発売時期：2023年初め頃

何故これらを購入してしまったのかと言えば、
- ローカルAIってGPGPUの場合、学習データがそのままメモリに乗っかる（GPGPUは仮想メモリ使えない）ので、８GBだと基本足りない
- jetson AGX Xavier(32GB)は中古だと１０万円未満で安くメモリが多い反面、CUDAコアが５１２個なのと、古いこともありJetPackが最新じゃないので、今後制約とか出てきそう
- jetson AGX orin は最新版なので、中古価格も２０万円を超えるが、orin nanoの倍のCUDAコア２０４８で、最新のJetPackが利用できる

何か最初から `jetson AGX orin` の中古買っとけば良かったって思った次第ですが、実際使ってみると思いの外「jetson AGX Xavier(ザビエル)」が使えるので、その点からすれば、最初に `ザビエル` 買って、色々足りなければ AGX orin 買う事を検討とかで良かったなあって思ったりしました（２しくじり）

## ちなみに：ラズパイ５＋SSD＋ケース買うなら、AmazonでRyzen7 5825Uの中華PC＋Ubuntuインストールのほうがコスパが良い

ちょうど最近買ったAmazon御用達の小型中華PC

https://www.amazon.co.jp/dp/B0DJQH5LLK?ref=ppx_yo2ov_dt_b_fed_asin_title

これ割引価格で買うと３万５千円ぐらいで買えるわけで、また Ryzen75875U = 8コア16スレッドで、AMDのGPU内蔵なので、普通に軽い３Dゲームぐらいなら普通に動きます。

メモリも最大６４GBまで増設可能なので、普通にメインPCで使えそうですが、例の中華あるあるのWindowsがボリュームライセンスなので、ちょっとWindowsは厳しい部分がありますが・・・。

あと欠点として搭載SSDがSATA接続なので、ここがNVME接続ならもっと良かった感じです。

しかしさすがRyzenCPUなだけあって faster whisper の音声文字起こしのAIをCPUで使った感じ、M1Macと同じぐらいの速度で変換できたので、普通に「速い」し、あと電力消費量も３０ワットと低いので、普通にUbuntuインストールして使うと、ラズパイ５より遥かにコスパが良いと言えます。

今回は短いですが、改めて２０２４年のローカルAI関連の散財を振り返ると、無駄遣いしたなあって思いました。

以上です。
At Coder 練習記録#1

## AtCoder練習記録
完全自分用です。最近atcoderを初めて感じたことは、普段使わないような関数やライブラリなどを使うことが多くて改めてPythonの勉強としてここに記録として残します。
といっても自分はまだプログラミング上級者でもないです。

### 問題文
<details><summary>Cut.0</summary>

問題文
実数 
X が小数点以下第 
3 位まで与えられます。

実数 
X を以下の条件を満たすように出力してください。

小数点以下の部分について、末尾に 0 を付けない
末尾に過剰な小数点を付けない
制約
0≤X<100
X は小数点以下第 
3 位まで与えられる
</details>
回答
<details><summary>回答例</summary>


```python
x = input()
x = float(x)
print(format(x,".12g"))
```
</details>

## format関数
使い方
```py
format(値, フォーマット指定子)
```
### .12gの意味
.12 有効数字を最大12桁までにする
g　不要な小数点以下の0を削除し出力
[Flutter x Firebase] FCMでのバックグラウンド通知がAndroidエミュレーターに表示されない

# 事象

開発中の Flutter アプリにバックグラウンド通知機能を実装したく、[公式のdoc](https://firebase.flutter.dev/docs/messaging/usage#background-messages)を見ながら進めていた

https://firebase.flutter.dev/docs/messaging/usage#background-messages
![スクリーンショット 2024-12-29 10.20.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900714/3c6cb727-0b04-5f4f-de6f-4f3c0ab0e268.png)

```dart
// main.dart

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print('バックグラウンドでメッセージを受け取りました');
}

void main() async {
  // 略
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());
  // 略
}
```

FCMから通知を作成し公開したところ、デバッグコンソールを確認する限り、メッセージの受信に成功してそうではあるが Android エミュレーター上には通知が表示されない

```
D/FLTFireMsgReceiver(22809): broadcast received for message
W/FirebaseMessaging(22809): Missing Default Notification Channel metadata in AndroidManifest. Default value will be used.
I/flutter (22809): バックグラウンドでメッセージを受け取りました
```
<img width='300' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900714/5759c2c1-16e3-20d5-f625-b3a68bcae93f.png' >

# 結論（原因）

Android エミュレーターの設定で、該当アプリの通知がONになっていなかった

エミュレーターの Setting > Apps > {該当アプリ} > Notifications が OFF に設定されており、通知を受け取らない設定になっていたことが原因だった

つまり、アプリに通知自体は到達していたものの、エミュレーターの設定により通知が表示されない状態になっていた

<img width='300' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3900714/b16e50ab-b851-eccf-717a-a33ffb9c605a.png' >

この設定を ON にしてから再度通知を送ることで表示された 🎉

# まとめ

これまで Android のデバイスに触れてきてないので単純なことに躓きがちw
2024年のふりかえりと2025年の抱負

# 2024年のふりかえり

### クリーンアーキテクチャ、UnitTestについて学ぶ(１月～７月)

あまり詳しい事は書ききれませんが、手がけたソフトウエア開発にクリーンアーキテクチャを導入してみたり、UnitTest行いやすい開発ってなんだろうということを考える機会をもてました。
- クリーンアーキテクチャだとUnitTestが行いやすい
- オブジェクト指向的を控えるUnitTestがやりやすい

### SWEST26に参加（8月）

[SWEST26](https://swest.toppers.jp/phx/)に初参加。
参加者の方々が、組み込み系の技術に限らず、さまざまな分野の専門家のみなさんで、皆さんといろいろ交流でき、とても有意義な時間を過ごすことができました。
台風の影響で、圧縮したスケジュールになってしまった事が残念ですが、いくつかのワークショップに参加もできました。

M5Stackを使った発表や話題が多くあり、M5Stackに興味をもつきっかけにもなりました。

### M5Stack MP135にNervesをポーティング（９月、１０月）

SWEST26がきっかけで、M5Stack MP135と出会いました。

https://docs.m5stack.com/en/core/M5CoreMP135

この機器に、[Nervesをポーティング](https://qiita.com/GeekMasahiro/items/dd214725bc1849b355ef)取り組みをおこないました。NervesはElixirで組み込み機器の開発ができるフレームワークで、興味をもっていたんですが、ポーティング作業を通じて理解が深まりとても良い経験ができました。
今後に活用したいとおもいます。

### AIの進歩

ChatGPTやGithub Copilotの進歩で、ちょっとくらい大変な事や、いままで思いつかなかったことが、できてしまうという変化があらわてきました
Nervesのポーティングも短期間でできたのもAIの活用があったからだと思います。

[LinuxのドライバーをChatGPTに頼んだら30分で完成した話](https://qiita.com/GeekMasahiro/items/326dcd7b25c40ebcc69b)

AIを活用したこの記事は、今年View数も多く、たくさんいいねもいただきました。

### Zinqを使ってみる（１１月～１２月）

2000年ごろ、FPGA開発をしていた時期がありました。当時は、Verilogが広まりはじめたところ。
四半世紀たった今では、ツールも進歩して非常に使いやすい状態になってました。

手始めに、AMD(Xilinx)のZinqを使ったボードを使って、FPGAの開発環境を整備中です。

# 2024年の目標のふりかえり

2024年初めに上げてた目標を書いていたので、それぞれについてふりかえってみます。

### Elixirを楽しむ

あまりElixirのプログラムは作ってないんですが、Nervesのポーティングを通じ楽しめました。

### AtCoderで水色になる

水色は、レーティング1200以上です。
今年のレーティングの最高は1099。残念ながら未達成でした。
コンテストには毎週参加で楽しめました。

### ElixirらしいOSSを作ってみる

OSSとして公開中できました。目標達成です。

https://github.com/masahiro-999/nerves_system_m5stack_core_mp135

https://github.com/masahiro-999/nerves_livebook

AtCoderは、ABCコンテストで想定されてるアルゴリズムについては一通り自分のものになった感はあります。趣味として楽しいのでもうちょっと続けてみようかとおもいます。
OSSはなにかできたらいいなぁという思いでしたが、Nervesの取り組みとなりました。まだまだ可能性がありそうなので、継続してみたいとおもいます。


# 2025年の抱負

- AIの処理を行うハードウエア（FPGAやNPU等）を扱えるようになる
- OSSに貢献する
- 1日30分の運動
TypeScriptで日本語の文字変換処理

## 概要

TypeScriptで実装する日本語の文字変換処理をメモする

## 1. ひらがなからカタカナに変換する

```ts
export const convertHiraganaToKatakana = (str: string) => {
  // ぁ-ん、ゔ、ゕ、ゖ
  return str.replace(/[\u3041-\u3096]/g, (s) => {
    return String.fromCharCode(s.charCodeAt(0) + 0x60);
  });
};
```

## 2. 半角カタカナを全角カタカナに変換する

```ts
// 半角カタカナのUnicode範囲 \uff61 ~ \uff9f を列挙
const CONVERT_MAP = {
  ガ: 'ｶﾞ',
  ギ: 'ｷﾞ',
  グ: 'ｸﾞ',
  ゲ: 'ｹﾞ',
  ゴ: 'ｺﾞ',
  ザ: 'ｻﾞ',
  ジ: 'ｼﾞ',
  ズ: 'ｽﾞ',
  ゼ: 'ｾﾞ',
  ゾ: 'ｿﾞ',
  ダ: 'ﾀﾞ',
  ヂ: 'ﾁﾞ',
  ヅ: 'ﾂﾞ',
  デ: 'ﾃﾞ',
  ド: 'ﾄﾞ',
  バ: 'ﾊﾞ',
  ビ: 'ﾋﾞ',
  ブ: 'ﾌﾞ',
  ベ: 'ﾍﾞ',
  ボ: 'ﾎﾞ',
  パ: 'ﾊﾟ',
  ピ: 'ﾋﾟ',
  プ: 'ﾌﾟ',
  ペ: 'ﾍﾟ',
  ポ: 'ﾎﾟ',
  ヴ: 'ｳﾞ',
  ヷ: 'ﾜﾞ',
  ヺ: 'ｦﾞ',
  ア: 'ｱ',
  イ: 'ｲ',
  ウ: 'ｳ',
  エ: 'ｴ',
  オ: 'ｵ',
  カ: 'ｶ',
  キ: 'ｷ',
  ク: 'ｸ',
  ケ: 'ｹ',
  コ: 'ｺ',
  サ: 'ｻ',
  シ: 'ｼ',
  ス: 'ｽ',
  セ: 'ｾ',
  ソ: 'ｿ',
  タ: 'ﾀ',
  チ: 'ﾁ',
  ツ: 'ﾂ',
  テ: 'ﾃ',
  ト: 'ﾄ',
  ナ: 'ﾅ',
  ニ: 'ﾆ',
  ヌ: 'ﾇ',
  ネ: 'ﾈ',
  ノ: 'ﾉ',
  ハ: 'ﾊ',
  ヒ: 'ﾋ',
  フ: 'ﾌ',
  ヘ: 'ﾍ',
  ホ: 'ﾎ',
  マ: 'ﾏ',
  ミ: 'ﾐ',
  ム: 'ﾑ',
  メ: 'ﾒ',
  モ: 'ﾓ',
  ヤ: 'ﾔ',
  ユ: 'ﾕ',
  ヨ: 'ﾖ',
  ラ: 'ﾗ',
  リ: 'ﾘ',
  ル: 'ﾙ',
  レ: 'ﾚ',
  ロ: 'ﾛ',
  ワ: 'ﾜ',
  ヲ: 'ｦ',
  ン: 'ﾝ',
  ァ: 'ｧ',
  ィ: 'ｨ',
  ゥ: 'ｩ',
  ェ: 'ｪ',
  ォ: 'ｫ',
  ッ: 'ｯ',
  ャ: 'ｬ',
  ュ: 'ｭ',
  ョ: 'ｮ',
  '。': '｡',
  '、': '､',
  ー: 'ｰ',
  '「': '｢',
  '」': '｣',
  '・': '･',
};
  
export const convertHalfKatakanaToFull = (str: string) => {
  let result = str;
  for (const [full, half] of Object.entries(CONVERT_MAP)) {
    result = result.replace(new RegExp(full, 'g'), half);
  }
  return result;
};
```

## 3. 全角英数字を半角英数字に変換する

```ts
export const convertFullAlphanumericToHalf(str: string) {
  return str.replace(/[Ａ-Ｚａ-ｚ０-９]/g, (s) => {
    return String.fromCharCode(s.charCodeAt(0) - 65248);
  });
}
```

## まとめ

日本語の文字変換処理の実装例を紹介しましたが、それを参考して逆変更も簡単に実装できるので割愛する。
Markdownのtableで行見出しを書きたい

## Markdownのtableには「列見出し」しかない

Markdownにはいくつか方言があるのですが、ぼくの観測範囲では、`thead > th`は書けても、いわゆる「行見出し」を書ける記法が見つかりませんでした（見た目だけ見出しっぽくする方法はいくらかある）。

ので、[michelf/php-markdown](https://github.com/michelf/php-markdown)をオーバライドして、行見出しを書けるようにするcomposerを作りました。

- [jidaikobo/php-markdown - Packagist](https://packagist.org/packages/jidaikobo/php-markdown)
- [jidaikobo-shibata/php-markdown - GitHub](https://github.com/jidaikobo-shibata/php-markdown)

以下のようなMarkdown記法で行見出しにします。

```markdown
| Header 1 | Header 2 |
|----------|----------|
| Row 1   :| Cell 1   |
| Row 2   :| Cell 2   |
```

セルの末尾に`:`を付与します[^1]。

## composerの使い方

```bash
composer require jidaikobo/php-markdown
```

上記コマンドで、vendorに必要なファイル群が入ります。

```php
require 'vendor/autoload.php';

use Jidaikobo\MarkdownExtra;

$table = "
| Header 1 | Header 2 |
|----------|----------|
| Row 1   :| Cell 1   |
| Row 2   :| Cell 2   |
";

$html = MarkdownExtra::defaultTransform($table);

echo $html;
```
出力されるものは以下のとおりです。

```HTML
<table>
<thead>
<tr>
  <th scope="col">Header 1</th>
  <th scope="col">Header 2</th>
</tr>
</thead>
<tbody>
<tr>
  <th scope="row">Row 1</th>
  <td>Cell 1</td>
</tr>
<tr>
  <th scope="row">Row 2</th>
  <td>Cell 2</td>
</tr>
</tbody>
</table>
```
`table`以外のMarkdown記法は[PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/)のままです。

## おまけ: captionも書きたい

最後の行で、`|:`で開始すると、`caption`になります。

```markdown
| Header 1 | Header 2 |
|----------|----------|
| Row 1   :| Cell 1   |
| Row 2   :| Cell 2   |
|:capt.
```
以下が出力されます。
```HTML
<table>
<caption>capt.</caption>
<thead>
<tr>
  <th scope="col">Header 1</th>
  <th scope="col">Header 2</th>
</tr>
</thead>
<tbody>
<tr>
  <th scope="row">Row 1</th>
  <td>Cell 1</td>
</tr>
<tr>
  <th scope="row">Row 2</th>
  <td>Cell 2</td>
</tr>
</tbody>
</table>
```

[^1]: なるべくそのまま見ても違和感が少ない記法にしたつもりですが、目立ち方が弱いかもしれません。
ファイルの上書きによるファイルの破損を回避する

Android開発でファイルの入出力を直接書くことはほぼないと思います。ただ、それ故に、あまり認知が進んでいないところかな？と思い立ったので書きます。

何らかの状態を保存する場合、特定のファイルに書き出し、次の更新ではそのファイルを上書き更新するということはよく行われます。
そこで、以下のように保存ファイルの書き換えを行うと、ファイルが破損してしまう可能性があります。

```kotlin
fun saveToFile() {
    val file = File("/path/to/savefile")
    file.outputStream().use { stream ->
        // 書き込み処理
    }
}
```

ファイルの上書きは、簡単に言えば
- 既存のファイルを削除し
- 書き込む内容を順次書き込んでいく

という処理になります。

書き換え中に何らかの問題が発生し、以下のような事態が発生した場合、
- 処理中のExceptionで処理を抜ける
- アプリのプロセスがKillされてしまう
- OSがハングアップする
- 端末の電源が切れる

書き換え前のデータは削除されていて、書き換え途中の読み出し不可能なデータが残ってしまったりします。
もちろんアプリ側で何をどう頑張っても回避できないファイル破損はありますが、アプリ側の工夫で回避できる部分は回避しましょう。

安全にファイルを上書きする場合は以下のようにします

```kotlin
fun saveToFile() {
    val file = File("/path/to/savefile")
    val tempFile = File(file.absolutePath + ".tmp")
    tempFile.outputStream().use { stream ->
        // 書き込み処理
    }
    Files.move(tempFile.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING)
```

保存したいファイル名で書き込むのではなく、別の名前のファイルとして書き出しを行い、完了したら、保存したいファイル名にリネームを行います。こうすることで
- リネーム完了していれば、更新後のファイル
- リネーム完了前は、更新前のファイル

が残ります。
書き換え途中の破損したファイルになってしまうことを防ぐことができます。
TypeScriptでthrottleとdebounce関数を実装する

## 概要

`scroll`イベントや`resize`イベントなど頻発するイベントに対して、毎回ハンドラーを実行するのが勿体無いし、パフォーマンス面に悪い影響が出る恐れはあるため、それを遅延するような関数が登場する。

## 基本概念

### 1. throttleの意味

- 何回に呼ばれても、指定の間隔時間内に最後の呼出だけが実行される
- 指定の間隔時間内に必ず1回が実行される

**利用例**：`scrollイベントハンドラーなどで使用される`
**解説**：`スクロール途中にハンドラー処理により画面表示内容が変わるような時に利用するのが適する`

つまり、実行する頻度を避けるが、一定の間隔で必ず実装する。

### 2. debounceの意味

- 何回に呼ばれても、最後の呼出だけが有効になる
- 最後の呼出の遅延時間を経ってたら実行される
- 遅延時間内に新たな呼出があったら、遅延時間がリセットされ、０から数える
- 極端に言うと、遅延時間の直前に連続で新たに呼び出すと永遠に呼ばれなくなる

**利用例**：`サジェストのキーワード入力フィールドにキーワードを変更する時のAPI通信処理`
**解説**：`途中のキーワードで取得したデータが必ず捨てられるのでdebounceすることで無駄な通信が避けられる`

つまり、相応しい遅延時間を設けることで、途中の連続操作による呼出を全て捨てる。

## 実装例

`react component`が`unmount`された後、遅延された処理を呼出しても意味ない場合が多いため、`unmount`する前にそれをキャンセルした方が良いのはほとんどだと思われる。従って、キャンセルできる仕組みを設ける。

TypeScriptでの実装例をメモする。

### 1. throttleの実装例

```ts
export const throttle = <Args extends unknown[]>(
  fn: (...args: Args) => void,
  interval: number,
): [(...args: Args) => void, () => void] => {
  // クロージャでタイマーIDと処理時間を覚える
  let timerId: ReturnType<typeof setTimeout>;
  let lastExecTime = 0;

  // 遅延処理を入れて元の関数をラップする
  const start = (...args: Args) => {
    const currentTime = Date.now();

    const execute = () => {
      fn(...args);
      lastExecTime = Date.now();
    };

    // 時間になってもtimerが実行されていない場合があるため、念のためクリアする
    clearTimeout(timerId);

    if (lastExecTime + interval <= currentTime) {
      // 前回の実行から指定の間隔時間を経ったら、関数を実行する
      execute();
    } else {
      // 前回の実行から指定の間隔時間を経ってなければ、タイマーを登録する
      const newInterval = lastExecTime + interval - currentTime;
      timerId = setTimeout(execute, newInterval);
    }
  };

  // 遅延された処理をキャンセル
  const cancel = () => {
    clearTimeout(timerId);
  };

  return [start, cancel];
};
```

### 2. throttleの実装例

```ts
export const debounce = <Args extends unknown[]>(
  fn: (...args: Args) => void,
  delay: number,
): [(...args: Args) => void, () => void] => {
  // クロージャでタイマーIDを覚える
  let timerId: ReturnType<typeof setTimeout>;

  // 遅延処理を入れて元の関数をラップする
  const start = (...args: Args) => {
    clearTimeout(timerId);
    timerId = setTimeout(() => {
      fn(...args);
    }, delay);
  };

  // 遅延された処理をキャンセル
  const cancel = () => {
    clearTimeout(timerId);
  };

  return [start, cancel];
};
```

## まとめ

純粋な`throttle`と`debounce`関数を色んな場面で活用することで、無駄な処理をなくして、より効率的な実装ができる。
Shallow CopyとDeep Copyの違いを徹底解説【Java編】

配列やオブジェクトをコピーするときに、**Shallow Copy（浅いコピー）** と **Deep Copy（深いコピー）** の違いをしっかり理解しておくことは、プログラミングでとても重要です。この記事では、その違いをわかりやすくコード付きで解説します。

---

## Shallow Copy（浅いコピー）とは？
**Shallow Copy** は、配列やオブジェクトの「参照」をコピーします。これにより、コピー元とコピー先は同じインスタンスを共有します。そのため、どちらかを変更すると、もう一方にも影響が及びます。

### **Shallow Copyの例**
```java
class Person {
    String name;

    Person(String name) {
        this.name = name;
    }
}

public class ShallowCopyExample {
    public static void main(String[] args) {
        // 元の配列
        Person[] original = {new Person("Alice"), new Person("Bob")};

        // Shallow Copy: 参照をそのままコピー
        Person[] shallowCopy = new Person[original.length];
        for (int i = 0; i < original.length; i++) {
            shallowCopy[i] = original[i]; // 同じオブジェクトを参照
        }

        // コピーを変更
        shallowCopy[0].name = "Eve";

        // 結果確認
        System.out.println("Original: " + original[0].name);  // "Eve"（元も影響を受ける）
        System.out.println("Shallow Copy: " + shallowCopy[0].name);  // "Eve"
    }
}
```

#### **結果**
```
Original: Eve
Shallow Copy: Eve
```

#### **ポイント**
- `shallowCopy` と `original` は同じオブジェクトを共有しています。
- コピー先で変更を加えると、元の配列にも影響があります。

---

## Deep Copy（深いコピー）とは？
**Deep Copy** は、配列やオブジェクトの中身をすべて新しく複製します。これにより、コピー元とコピー先は完全に独立した状態になります。どちらかを変更しても、もう一方に影響は及びません。

### **Deep Copyの例**
```java
class Person {
    String name;

    Person(String name) {
        this.name = name;
    }

    // Deep Copyを作るためのメソッド
    public Person deepCopy() {
        return new Person(this.name);
    }
}

public class DeepCopyExample {
    public static void main(String[] args) {
        // 元の配列
        Person[] original = {new Person("Alice"), new Person("Bob")};

        // Deep Copy: 新しいオブジェクトを作成
        Person[] deepCopy = new Person[original.length];
        for (int i = 0; i < original.length; i++) {
            deepCopy[i] = original[i].deepCopy(); // 新しいオブジェクトを作成
        }

        // コピーを変更
        deepCopy[0].name = "Eve";

        // 結果確認
        System.out.println("Original: " + original[0].name);  // "Alice"（元は影響を受けない）
        System.out.println("Deep Copy: " + deepCopy[0].name);  // "Eve"
    }
}
```

#### **結果**
```
Original: Alice
Deep Copy: Eve
```

#### **ポイント**
- `deepCopy` は `original` とは独立した新しいオブジェクトを持ちます。
- コピー先を変更しても、元の配列には影響がありません。

---

## Shallow Copy と Deep Copy の違いまとめ

| 項目             | Shallow Copy                          | Deep Copy                            |
|------------------|-------------------------------------|-------------------------------------|
| **コピー内容**   | 配列やオブジェクトの「参照」をコピー   | 配列やオブジェクトの「中身」をコピー |
| **変更の影響**   | 元のデータとコピー先が影響を及ぼす     | 元のデータとコピー先は独立している   |
| **コードの違い** | `shallowCopy[i] = original[i];`       | `deepCopy[i] = original[i].deepCopy();` |

---

## どちらを使うべきか？
- **Shallow Copy**:
  - メモリを節約したい場合
  - 元のオブジェクトとコピー先で同じ参照を共有するのが意図的な場合
- **Deep Copy**:
  - コピー元とコピー先を完全に独立させたい場合
  - データを変更しても他方に影響を与えたくない場合

---

この記事を参考に、Shallow CopyとDeep Copyを使い分けられるようになりましょう！コードの使い方や実装について気になる点があればコメントで教えてください！