OmniAICreator/Qiita-1.07M huggingface dataset:
本番環境のNuxt 3アプリのコードを難読化する方法

Nuxt 3アプリをVercelで配信する際、コードの難読化（obfuscation）を実現するためには、以下のような設定やツールを利用します。難読化は、クライアントサイドで配信されるJavaScriptコードを解析しにくくする目的で行います。

---

## 1. **ビルド時に難読化を組み込む**

Nuxt 3では、ビルドプロセス中にコードを難読化するために外部ツールを組み込むことができます。以下の方法を利用します。

### (1) WebpackまたはVite用の難読化プラグインを利用

Nuxt 3はデフォルトでViteを利用しますが、Webpackもサポートされています。どちらでも難読化プラグインを追加できます。

#### Viteの場合

1. 必要なパッケージをインストールします：
   ```
   npm install vite-plugin-obfuscator --save-dev
   ```
   ‌
2. `nuxt.config.ts`に以下を追加します：
   ```typescript
   import { defineNuxtConfig } from 'nuxt'
   import obfuscator from 'vite-plugin-obfuscator'
   export default defineNuxtConfig({
     vite: {
       plugins: [ obfuscator({ // 難読化オプション（例: 制御フローの難読化を有効にする）
         obfuscationOptions: {
           compact: true,
           controlFlowFlattening: true,
           deadCodeInjection: true,
           debugProtection: false
         } })
       ]
     }
   })
   ```
   ‌

#### Webpackの場合

1. Webpack用の難読化プラグインをインストール：
   ```
   npm install javascript-obfuscator-webpack-plugin --save-dev
   ```
   ‌
2. NuxtのWebpack設定を拡張します：
   ```typescript
   import JavaScriptObfuscator from 'javascript-obfuscator-webpack-plugin'
   export default defineNuxtConfig({
     build: {
       extend(config) {
         config.plugins.push(
           new JavaScriptObfuscator({
             rotateStringArray: true,
             stringArray: true,
             stringArrayThreshold: 0.75
           })
         )
       }
     }
   })
   ```
   コードをコピーする

---

## 2. **配信時の注意**

コードの難読化は以下の点に注意して行います：

- **デバッグの難しさ**：難読化されたコードはデバッグが非常に難しいため、本番環境でのみ適用するのがおすすめです。
- **パフォーマンスへの影響**：難読化によりコードサイズが増大する場合があります。必要に応じて軽量化を意識してください。
- **Vercelでの対応**：Vercelは`nuxt build`の成果物をそのまま利用してデプロイします。難読化を含んだビルド成果物が生成されるため、特別な追加設定は不要です。

---

## 3. **サーバーサイドコードの保護**

サーバーサイド（エッジやAPIなど）ではコードが公開されませんが、難読化が必要な場合は、サーバーコードにも同様の設定を適用できます。

---

## 4. **ローカルでの動作確認**

難読化後のコードが意図通り動作するか、本番環境の設定を再現して十分にテストしてください。

---

## 5. **難読化の代替策**

難読化は安全性向上のための手法の一つに過ぎません。合わせて以下の施策を検討してください：

- クライアントサイドで機密データを処理しない。
- APIキーやシークレットはバックエンドで管理する。
- Content Security Policy (CSP)を設定してコードの保護を強化する。

---

これらを実施することで、Vercelで配信されるNuxt 3アプリケーションのコードを難読化できます。
【初心者向け】Amazon Comprehendでキーフレーズを取得し、Amazon Pollyで音声を生成してみた

## はじめに
AWS初心者です。AWSの基本知識をキャッチアップすべく、色々触りながら学習中です。<br>今回は生成AIのサービスであるAmazon ComprehendとAmazon Pollyを触ってみました。初心者向けの内容となっておりますので、温かい目で見て頂ければ幸いです。

## 利用するAWSサービス
- Comprehend
- Polly
- Lambda(Python3.13)
- S3
- IAM

## 実践手順
### S3にバケットを用意する
音声データを出力する先のバケットを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936702/8cb10ae8-8e37-3118-7436-b91ac8087df0.png)

これでS3側の設定は完了です。

### IAMロールを作成する
1. ユースケースを選択する
IAMからロールを選択し、新規にロールを作成します。今回は、LambdaからS3へのアクセスを許可するロールを作成するため、ユースケースには「Lambda」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936702/5a23cdb3-dd14-6d3a-3c17-2725e1a79f0e.png)
1. ポリシーを追加する
ロールにアタッチするポリシーを追加します。今回は、Amazon Comprehend、Amazon Polly、S3へのアクセスが必要なため、それぞれのポリシーを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936702/136c9e3d-313f-1b2b-4c8a-cd5f4ca0a0fb.png)

1. ロールを作成する
ロール名を入力し、ロールを作成します。作成したロールは後述のLambda関数で利用するため、分かりやすい名前にします。

これでIAMロールの作成は完了です。

### Lambda関数を作成する
1. 関数を作成する
今回はPythonでプログラムを書くため、ランタイムは「python 3.13」を選択します。
関数名はプログラムの内容がイメージしやすい名前にします。
ロールには前述で作成したIAMロールを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936702/9419c643-ab41-9462-02eb-68fea58617c3.png)

1. 必要な設定を変更する
今回はタイムアウト時間を2分に変更します。必要に応じてコードから参照する環境変数を設定してください。

### コードの実装
#### サンプルコード
```python:lambda_function.py
import boto3

def lambda_handler(event, context):
    # AWSクライアントの初期化
    s3_client = boto3.client('s3')
    polly_client = boto3.client('polly')
    comprehend_client = boto3.client('comprehend')

    # 対象となるテキストの定義
    text = "write your sample text."

    # テキストからキーフレーズを取得
    response = comprehend_client.detect_key_phrases(
        Text = text,
        LanguageCode = 'ja'
    )
    # キーフレーズ(リスト)から文字列を取得
    content = ""
    key_phrases_list = [phrase['Text'] for phrase in response['KeyPhrases']]
    for index,item in enumerate(key_phrases_list):
        content += item + "," 

    # 音声データの生成
    responseVoice = polly_client.synthesize_speech(
        Text = content,
        OutputFormat = 'mp3',
        VoiceId = 'Mizuki'
    )

    # 音声データを取得
    audioData = responseVoice['AudioStream'].read()

    # S3バケット名と保存するファイル名
    s3_bucket_name = "your-bucket-name"
    s3_file_name = "your-file-name"

    # S3に音声データをアップロード
    s3_client.put_object(
        Bucket = s3_bucket_name,
        Key = s3_file_name,
        Body = audioData,
    )

    return {
        'statusCode': 200,
        'body': f"ファイル '{s3_file_name}' が S3 バケット '{s3_bucket_name}' に正常にアップロードされました。"
    }

```
### 実行結果
Lambdaへデプロイして、実行するとS3に音声データ(mp3)が保存されていることを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936702/148d258c-8086-65e0-86f4-5ce56ce92241.png)

## おわりに
当初は、取得したWeb上のデータ(ニュース記事など)をComprehendを使って要約しようと思っていましたが、API「syntax」の上限が5000Byteだったり、日本語をサポートしていなかったり躓いたため、結果的にあまり実用的ではない内容になってしまいました。<br>AWSのサービスを理解するという最低限の目的は達成できたので、次回以降はもう少し実用的な仕組みを目指してトライしてみようと思います。
Power AutomateのフローAPI実行数に関する備忘録

# API実行数の確認方法
Power Automateデザイナーの詳細画面［分析］からPower BI形式で確認できます。確認できるのは、日別でフローのアクション要求数（=API実行数）です。

![スクリーンショット 2024-11-21 011649.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/e9e5efe8-f336-5a0b-e641-40df1740cb69.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/97178e0e-af81-4a51-efb6-8d7a671719cc.png)


# API実行数のカウント方法
Power Automateの製品仕様として、API実行数の消費対象は、アクションの［設定］⇒［マイコネクション］から接続したアカウントです。

![スクリーンショット 2024-11-21 012550.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/99bf0531-3ffd-7c96-bd27-407eefe051cb.png)

<br>

例えば、以下のケースを仮定します。
クラウドフローの所有者は、user1@microsoft.com
クラウドフローのAアクションの接続アカウントが、user2@microsoft.com
クラウドフローのBアクションの接続アカウントが、user3@microsoft.com

このような場合でクラウドフローを所有者user1@microsoft.comで実行した場合、API実行数の消費カウントは、user1が0回、user2とuser3が1回となります。
|アカウント|フロー所有者|アクションA|アクションB|API実行数|
|---|:-:|:-:|:-:|--:|
|user1@microsoft.com|〇|||0|
|user2@microsoft.com||接続||1|
|user3@microsoft.com|||接続|1|

# API要求数の制限
1ユーザー1日あたりのAPI要求数の制限に関しては、以下記事をご参照ください。

https://learn.microsoft.com/ja-jp/power-platform/admin/api-request-limits-allocations#licensed-user-request-limits
【Android】アーキテクチャーとして Google が推奨していること

公式リファレンスも分かりやすくなってきましたね。

https://developer.android.com/topic/architecture/recommendations

# 🧑🏻‍💻 Layered Architecture

```
UI Layer
  |
Coroutine
  |
DataL Layer
  |
Repository
```

![sc 2024-11-21 at 0.47.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/fdc045a9-d85d-c984-1d26-370fe6aae5d6.png)

[(つづく...)](https://android.benigumo.com/20241121/recommendations-for-android-architecture/)


# 🧑🏻‍💻 引用

以下にまとめられています。

https://android.benigumo.com/20241121/recommendations-for-android-architecture/
useAsyncData 機能（Nuxt3）の重複リクエスト（HTTP）を排除する仕組みを解説

Nuxt 3 の `useAsyncData` 機能がバックエンド（サーバーサイドレンダリング）とクライアントサイドでの重複HTTPリクエストを排除する仕組みは、**データのキャッシュと再利用**を活用しています。以下の流れで実現されています：

---

### 1. **サーバーサイドでデータを取得**

- サーバーサイドレンダリング（SSR）の際、`useAsyncData` を利用して非同期データを取得します。
- サーバーサイドでデータを取得すると、その結果が HTML と一緒に生成され、レスポンスとしてクライアントに送信されます。
- データは `Nuxt payload` としてページの HTML 内に埋め込まれます。このデータは `<script>` タグ内に JSON フォーマットでシリアライズされ、クライアント側で直接利用可能になります。

---

### 2. **クライアントサイドでのデータ利用**

- クライアントがページを受け取ると、`useAsyncData` はまずサーバーから埋め込まれた `Nuxt payload` を確認します。
- `useAsyncData` は、リクエストしたデータが既に `payload` に存在している場合、新たにHTTPリクエストを送らず、そのデータを直接再利用します。
- この仕組みによって、クライアントでの同じデータに対する重複リクエストが排除されます。

---

### 3. **再利用のキー（Key）管理**

- `useAsyncData` は、データ取得のリクエストごとに一意のキー（デフォルトでは `useAsyncData` に渡された名前）を使用します。
- このキーを基に、サーバーサイドで取得されたデータが `payload` に保存され、クライアントでの参照時に利用されます。

---

### 具体的な流れをコードで説明

```javascript
export default defineComponent({
  async setup() {
    const { data } = useAsyncData('exampleData', () =>
      fetch('https://api.example.com/data').then(res => res.json())
     );
    return { data };
  },
});
```

コードをコピーする

#### サーバーサイドでの流れ

1. サーバーが `fetch` を実行してデータを取得。
2. データをページの `Nuxt payload` に埋め込む。
   - 例:
     ```html
     <script type="application/json" id="__NUXT_DATA__">
       {"data":{"exampleData":{...}}}
     </script>
     ```

#### クライアントサイドでの流れ

1. ページロード時、`useAsyncData` はまず `__NUXT_DATA__` の内容を確認。
2. `exampleData` が既に存在していれば、再度リクエストを送らずにそのデータを利用。

---

### 4. **キャッシュの利用とフレッシュデータの取得**

- キャッシュはデフォルトで有効ですが、必要に応じてリフレッシュ可能です。
- `useAsyncData` のオプションで `lazy` や `default` を設定することで、データの取得タイミングやキャッシュ戦略を制御できます。

例:

```javascript
useAsyncData('exampleData', fetchFunction, { lazy: true, default: () => [] });
```

---

### 結果的なメリット

1. **効率的なデータ取得**: SSR で一度取得したデータをクライアントでも再利用。
2. **重複リクエストの排除**: サーバーとクライアント間でデータを共有する仕組みによって不要なHTTPリクエストを防止。
3. **シームレスな体験**: ユーザーはサーバーとクライアントのデータ取得プロセスの違いを意識せず、高速なデータ提供を享受。

この仕組みが、Nuxt 3 の強力なデータ管理能力の基盤となっています。
【超基礎】TypeScriptにおける構造的型付けについて

# 前提
この記事は、初学者の私が、サバイバルTypeScriptで学んだこと+調べたことをまとめたものになります。

従って、経験則に基づいた発言ではないため、一部慣習とは違っていたり、認知にずれがあったりする可能性がありますので、ぜひコメントで指摘していただけると幸いです。

https://typescriptbook.jp/

# 要約
- TSでは**型の構造に基づいて型を区別する**
- 構造的型付け ⇔ 名前的型付け
- 型の名前が違っていても、**必要なプロパティやメソッドが一致していれば代入可能**
- **意図しない互換性に注意する必要がある**が、`private`メンバーやブランドで回避できる

# 構造的型付けとは？
**名前でなく、型の構造に基づいて型を区別する**方法。オブジェクト型の様な、複数のメソッドやプロパティを持つ型において、**柔軟性の高い代入が可能となる**。

TypeScriptのほかにもGoなどで採用されており、一般的に名前的型付けと大別される。
```typescript:
//構造が同じで名前が違う2つの型
Class Person1{
    name() {}
}
Class Person2{
    name() {}
}

const person1: Person1 = new Person1;
const person2: Person2 = person1;//構造が同じなので、エラーは発生しない
```


## 名前的型付けについて
- **型同士の区別を型の名前で行う**
- `Java`や`C#`、`Swift`で採用されている。
```Java:Java
//構造が同じでクラス名が違う2つの型
class Person1 {
    void name() {}
}
class Person2 {
    void name() {}
}


Person1 person1 = new Person1();
Person2 person2 = person1 //Error　別の型という扱い
```

## 構造的部分型
**異なる型のインスタンスについて、必要なプロパティ、メソッドがそろっていれば代入できる**。例えば、下のコードに示したような

`name,talk()を持つインスタンス`　⇐　`name,age,talk(),walk()を持つインスタンス`

の代入が可能となる **※逆は不可**

:::note
要求するプロパティ以外のものは使われず、代入の際に無視される
:::
```typescript
class Person1{
    name: string;
    age: number;
    
    constructor(name: string,age: number){
        this.name = name;
        this.age = age;
    }
    
    talk(){}
    
    walk(){}
}

class Person2{
    name: string;
    
    constructor(name: string,age: number){
        this.name = name;
    }

    talk() {}
}

const person1: Person1 = new Person1("Taro",15);

const person2: Person2 = person1; //可能
const personOne: Person1 = person2 //Error 
//person2はPerson1クラスに要求されるプロパティやメソッドを持っていない
```

## 名前的型付けでは？
名前的型付けでは継承を使うことで、名前的部分型として、オブジェクト間の型関係を表現する

:::note warn
TypeScriptでも継承は使うが、**親クラスのインターフェースを守るため**に使われ、メソッドの引数や返り値の変更はエラーになる。
:::
``` Java
class Person1 extends Person2
```
## 構造的型付けが抱える問題
### 概要
構造的型付けが抱える問題として挙げられるのが、**型間の不要な互換性**である。構造が同じであれば同じ型であると認識してしまうことで、本来全く関係のない型同士を同じものとしてしまう。
### 例
```typescript
class Person{ 
    move() {}
}

class Car{
    move() {}
}

//全く関係のない車と人間を同じ型だと認識してしまう
const person: Person = new Person();
const car: Car = person;
```
### 解決策
**1. privateメンバーの追加**
`private`修飾子を使用することで、型は同じでもクラス固有のものを作成できる。

::: note warn
private修飾子で宣言されたプロパティは、**外から直接呼び出せない**ことに注意する
:::
```typescript
class Person{
    private name:string 
}
```
**2. ブランド型の定義**
各クラスに異なるブランド型のプロパティを追加することで、クラス間の区別が可能になる。

:::note
ブランド名を同じにすることで、クラスのグループ化が可能になる
:::
```typescript
class Person{
    __brand: "person"
    move(){}
}

class Car {
    __brand: "car"
    move(){}
}
```

## まとめ
以上になります。型でガチガチに縛られているイメージのあるTypeScriptですが、必要に応じて柔軟性を持たせている部分は綺麗ですね。

当方初学者なため、認知のずれや、モダンな開発現場ではもう使わない表現などがありましたらコメントで指摘していただけると幸いです。😸

### 参考資料
https://typescriptbook.jp/reference/values-types-variables/structural-subtyping

https://qiita.com/ConquestArrow/items/960d0e3a25fca4897787

https://qiita.com/suin/items/52cf80021361168f6b0e

https://qiita.com/SP-ya/items/b3cc156cc0898915d8c5
LeetCodeを1日1題解いてみる (day22)

22日目に取り組んだ問題はこちら！

# 110. Balanced Binary Tree

https://leetcode.com/problems/balanced-binary-tree/description/

## 問題文
Given a binary tree, determine if it is height-balanced


## 僕の回答
```py
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return True

        def calcDepth(root: Optional[TreeNode]) -> tuple[int, bool]:
            if not root:
                return (-1, True)
            l_depth, is_l_balanced = calcDepth(root.left)
            r_depth, is_r_balanced = calcDepth(root.right)

            if not is_l_balanced or not is_r_balanced:
                return (0, False)

            return (max(l_depth, r_depth)+1 , True) if abs(l_depth-r_depth) <= 1 else (0, False)

        _, result = calcDepth(root)
        return result
```

## より効率の良い回答例
特になし

### コメント
ヒントなしで、他の人の解答例と同じロジックで実装できたので、嬉しい。pythonの書き方も慣れてきた。ただ、関数や変数名がわかりにくいので、簡素でわかりやすいものを思いつけるように頑張る。
`if not node:`ここで返すべき深さは`-1`ではなく、`0`の方が良さそう...？

### 次の問題はこちら!
https://qiita.com/h_y_s_d/items/5d3f55912b82def8c23c
【Day1】Tauriでエンジンからゲームを作ってみよう【QAC24】


# 前略

久しぶり！ 1 年ぶりの Qiita Advent Calendar だね！ (それは当たり前)

今年は、Tauri を使ってゲームエンジンからゲームを作ってみようと思います。
ちゃんと 25 日分書ききれるかどうかは正直微妙ですが、書ききれなかったら書ききれなかったということで...

# GUI 作りたいよな。

皆様、CUI アプリケーション(TUI)は好きですか？
もちろん、かっこよくていいですよね。

でも...やっぱり、マウス使うタイプの我々にとっては GUI アプリのほうが使いやすいですよね。
しかし、どうしても GUI アプリケーションの開発にはコストがかかる！！！

前回のアドベントカレンダーでも.NET MAUI を使って GUI アプリケーションを作ってみましたが、やっぱり C#はちょっと慣れないですし、XAML もちょっと...という方も多いのではないでしょうか？
私もその一人です。

Electron なんて便利なものもありますが、フロントエンドとバックエンドが同じ JavaScript なのに、仕様が違うせいで、なんかどっちの JavaScript を書いてるのか分かんなくなってそれでライブラリもごちゃごちゃで...うーん...

「...そんなあなたにお勧めの商品...ありますよ。」

# Tauri とは

Tauri は、Rust 製の GUI アプリケーションフレームワークです。

はーい、そこの「Rust って聞いてｳｯってなった」方々～
私もです。

確かに Rust はナウくて、メモリ安全で、動作も高速で...とかいろいろ言われても、やっぱりラーニングコストは高いと思います！
しかし！　そんなあなたにこそ、Tauri をお勧めしたい！！！！

Tauri は、バックエンド部分を Rust で書き、フロントエンド部分を HTML/CSS/JavaScript(TypeScript)や、React、Vue や Svelte で書くことができます。
ここまでは、バックエンドの言語が変わっただけの Electron ですよね。

しかし、Tauri の魅力はここからです。

Electron は、Chromium を使っているため、アプリケーションのサイズが大きくなりがち、メモリ消費も多いです。
しかし、Tauri は、Chromium を使わず、OS に搭載されている WebView を使っているため、アプリケーションのサイズが小さく、メモリ消費も少ないです。
更には、WebView を使用するおかげで、App Store や Google Play Store にもアプリケーションを提出することができます。

そして何より Tauri は初心者に割と優しい設計になっていて、Rust の知識がなくても、簡単にアプリケーションを作ることができます。
Rust がバックエンドで動いているが、Rust の知識がほぼなくても動かせてしまう。
なんなら、簡単な GUI アプリケーションなら Rust に一切触れずに作ることもできます。
何を言っているが分かんないかもしれませんがそのまんまの意味です。

Tauri 側で API を用意しており、フロントエンド側でそれを呼び出すだけで、フロントエンドからは直接いじれないファイル操作などが行えてしまいます。

もちろん、Electron(+TypeScript)であれば、型を同じように書けばいいだけだから楽...など双方にメリットはありますが、今回は「Electron の代替を目指す Tauri 君」を使ってみたいと思います。

# このアドベントカレンダーでやること

このアドベンドカレンダーでは、つい直近リリースされた、Tauri v2 を使ってゲームを作っていきます。

さっき、Rust の知識がなくても作れると言いましたが、今回のアドベントカレンダーでは Rust のコードも書いていきます。
ただ、私も Rust に関してはガチの初学者なので、間違いがあるかもしれませんが、その辺はご了承ください。

そして、フロントエンド部として Vanilla(HTML/CSS)と TypeScript を使っていきます。
そのため、いわゆる Web ページ制作(HTML/CSS)と、これまた Web ページでよく使われる JavaScript という言語の拡張版に値する TypeScript という言語についても触れていき、理解してもらいたいと思います。

Rust も TypeScript も`型`という概念が非常に重要になっていきます。
そのため、型についてもこの記事を通してぜひ理解していって、その他のプログラミング言語にも応用できるようにしていって欲しいなと思います。

# まとめ

という訳でこれから 25 日間、よろしくお願いいたします。
なお、この記事...というか Rust を書いていくうえで、性能が低い PC だとコンパイルに時間がかかって、非常にストレスを感じるかもしれません。
なので、出来る限り性能が高い PC で作業することをお勧めします。
（とはいっても一般的なノーパソぐらいで大丈夫（その代わりパフォーマンスモードとかにしてファンうるさくしちゃおう））

あと、Windows での開発を想定していますので！！
macOS や Linux の方は、その辺の違いを各自調べていただけると幸いです。
（でも Apple Silicon Mac のほうが Rust のコンパイル早いって聞いた...）

それでは、また明日もよろしくお願いします！
【差分プライバシ】レニィ差分プライバシとは？？【RDP】

# レニィ差分プライバシとは何かについて学ぶ

差分プライバシをより一般化した概念であるレニィ差分プライバシについて学習していこうと思う

## きっかけ

卒業研究で必要になったから

## 定義

[参考文献](https://arxiv.org/abs/1702.07476)

$$
D_{\alpha}(P||Q)=\frac{1}{\alpha - 1}\log \int_x P(x)^\alpha Q(x)^{1-\alpha}dx \le \varepsilon
$$

ここで、
- ${P,Q}$は隣接DBを学習したモデルによる出力分布
    - 例えば、${\{0, 1, 1, 1, 1\}}$を学習したモデル$P$において、$p_1=0.8$
    - $0, 1, 1, 1$を学習したモデル$Q$において、$p_1 = 0.75$
    - これが違いすぎたらプライバシ保護できてないよねってこと
- 非対称
    - ${D_{\alpha}(P||Q) \ne D_{\alpha}(Q||P)}$

情報理論で学んだKL(カルバックレイバー)ダイバージェンスの一般化された形
（懐かしい）

$$
D_{\text{KL}} (P||Q) = \int P(x)\log\frac{P(x)}{Q(x)}dx
$$


## 導出

レニィダイバージェンスの目的は、**隣接DBを学習したモデルの出力結果が違いすぎたらまずい**指標を作ること
よって、
- まず、あるデータポイントに関する**モデルの出力結果の違い**を定量的に測る
- データポイント全体を集める

### モデルの出力結果の違い

$$
\left(\frac{P(x)}{Q(x)}\right)^\alpha
$$

ここで、
- $x\sim Q$であり、$Q$が出力分布の基準
- $P(z)$は、$\Pr[P(X = z)]$
    - つまり、$Q$から出力されるあるデータポイント$x$が、隣接DBを学習したモデル$P$でどれくらいの確率で出力されるか？ということ
    - 例えば、先ほどの例で言えば、${P(1)=0.8}$, $Q(1)=0.75$なので、$\left(\frac{0.8}{0.75}\right)^\alpha$

### データポイント全体を集める

先ほどの値は、$Q$から出力される一つのデータポイントに過ぎなかったので、それを集める

$$
\begin{equation}
\begin{split}
\mathbb E_{x\sim Q}\left[\left(\frac{P(x)}{Q(x)}\right)^\alpha\right]&=\int\left(\frac{P(x)}{Q(x)}\right)^\alpha Q(x)dx \\
&=\int P(x)^{\alpha}Q(x)^{1-\alpha}dx
\end{split}
\end{equation}
$$

忘れていたけど

$$
\mathbb E_{x\sim Q}\left[f(x)\right]=\int\left(f(x)\right) Q(x)dx
$$

の変形に注意（具体的に考えればわかる）

つまり、先ほどの例で言えば$\alpha=1$の時、$\frac{0.8}{0.75}\cdot 0.75 + \frac{0.2}{0.25}\cdot 0.25$ってことですな。
NGINXプロセスが謎に落ちる？考えられる要因とは？

### 1. **設定ファイルの問題**

NGINXは設定ファイルに問題があると、正常に起動できない場合があります。

- **原因**
  - `nginx.conf` やその他の設定ファイルの文法エラーや構文ミス。
  - 必要なディレクティブや値が欠如している。
  - 設定に使用しているパスが間違っている。
- **確認と対処**
  - 設定をテスト:
    ```
    sudo nginx -t
    ```
    ‌
  - エラーメッセージに従って設定を修正。

---

### 2. **リソース不足**

サーバーのリソースが不足している場合、NGINXがクラッシュする可能性があります。

- **原因**
  - メモリ不足（特に大量のリクエストが発生している場合）。
  - ファイルディスクリプタ数の上限 (`ulimit`) に達している。
  - CPU負荷が高すぎる。
- **確認と対処**
  - サーバーのリソース状態を確認:
    ```
    free -h # メモリの確認 top # CPU/メモリ使用状況を確認 ulimit -n # ファイルディスクリプタの確認
    ```
    ‌
  - 必要に応じてシステムリソースの割り当てを増加。

---

### 3. **ポート競合**

NGINXがバインドしようとしているポートが、他のプロセスによって使用されている場合。

- **原因**
  - 既に同じポートを使用する別のプロセスが存在する。
- **確認と対処**
  - ポートの使用状況を確認:
    ```
    sudo netstat -tuln | grep 80
    ```
  - 他のプロセスを停止するか、NGINXのポート設定を変更。

---

### 4. **SELinuxやファイアウォールの制約**

セキュリティ設定がNGINXの動作を妨げている可能性があります。

- **原因**
  - SELinuxがNGINXのポートやファイルアクセスをブロックしている。
  - ファイアウォールで必要なポートが開放されていない。
- **確認と対処**
  - SELinuxのログを確認:
    ```
    sudo cat /var/log/audit/audit.log | grep nginx
    ```
    ‌
  - 必要なポートやアクセスを許可:
    ```
    sudo setsebool -P httpd_can_network_connect on
    sudo firewall-cmd --add-service=http --permanent
    sudo firewall-cmd --reload
    ```

---

### 5. **権限の問題**

NGINXが必要なファイルやディレクトリにアクセスできない場合、終了することがあります。

- **原因**
  - 設定ファイルやログディレクトリの権限が不適切。
  - ユーザーが必要なリソースへのアクセス権を持っていない。
- **確認と対処**
  - 権限を確認:
    ```
    ls -l /path/to/nginx.conf
    ls -ld /var/log/nginx
    ```
    ‌
  - 必要に応じて権限を変更:
    ```
    sudo chown nginx:nginx /path/to/nginx.conf sudo chmod 644 /path/to/nginx.conf
    ```

---

### 6. **モジュールやライブラリの不整合**

NGINXで使用しているモジュールやライブラリが正しく動作していない可能性があります。

- **原因**
  - カスタムモジュールのインストールミス。
  - 使用中のNGINXバージョンと互換性のないモジュール。
- **確認と対処**
  - ログを確認してエラーの原因を特定:
    ```
    sudo tail -f /var/log/nginx/error.log
    ```
    ‌
  - 必要に応じてモジュールを再インストールするか、互換性のあるものに変更。

---

### 7. **クラッシュやセグメンテーションフォルト**

NGINX自身に問題があり、セグメンテーションフォルトが発生する場合。

- **原因**
  - バグや古いバージョンのNGINX。
  - 不正な構成や異常なトラフィック。
- **確認と対処**
  - エラーログを確認:
    ```
    sudo tail -f /var/log/nginx/error.log
    ```
    ‌
  - NGINXを最新バージョンにアップグレード:
    ```
    sudo apt update && sudo apt upgrade nginx
    ```

---

### 8. **OSやカーネルの問題**

システムレベルの問題でNGINXが終了することもあります。

- **原因**
  - カーネルパニックやシステムリソース管理の問題。
- **確認と対処**
  - システムログを確認:
    ```
    sudo journalctl -xe
    ```
    ‌
  - 必要に応じてシステムのアップデートや再起動を実施。

---

### まとめ

以下の優先順位でトラブルシューティングを進めると効率的です：

1. NGINX設定 (`nginx -t`) の確認。
2. リソース不足やポート競合のチェック。
3. ログ (`/var/log/nginx/error.log` やシステムログ) の解析。
4. SELinuxや権限の確認。
5. 必要に応じてアップデートや再インストール。

それでも解決しない場合は、具体的なログのエラーメッセージを確認して追加の情報を特定するのが効果的です。
CLIとCloudFormationでLambdaを作成する際のセキュリティ注意点

## はじめに

簡単な復習と備忘録のために、CLIもしくはCloudFormationでLambdaを作成する際の注意点を記事にしたいと思います。今回は簡単ですが、次回以降の記事では詳細な検証を行っていきたいと思います。

CLIやCloudFormationでAWS Lambda関数を作成する場合、デフォルトではリソースベースポリシーは自動的に作成されません。これはマネジメントコンソールでLambda関数を作成する場合はリソースベースポリシーが作成されます。

## リソースベースポリシーとは

リソースベースポリシーは、そのリソース（この場合はLambda関数）自体に設定されるポリシーで、他のAWSアカウントやサービスがそのリソースにアクセスする際の権限を定義します。このポリシーを適切に設定することで、アクセス制御を厳密に行うことができます。

## 最小権限の原則の重要性
最小権限の原則を守ることで、セキュリティリスクを最小限に抑えることができます。そのためには、リソースベースポリシーを設定することで、以下の点を明確に制御できます。

誰がLambda関数にアクセスできるか
- 特定のAWSサービス、IAMユーザー、ロール、または他のAWSアカウントに限定できます。

どのようなアクションが許可されているか
- lambda:InvokeFunctionなど、許可する操作を限定できます。


## リソースベースポリシーが不適切な場合のリスク

意図しないアクセスの許可：リソースベースポリシーを不適切に設定すると、他のアカウントやサービスにLambda関数へのアクセスを許可してしまう可能性があります。特に、Principalに"*"を指定すると、全てのユーザーにアクセスが許可されてしまいます。
セキュリティリスクの増大：第三者がLambda関数を不正に呼び出したり、操作されるリスクがあります。
## AWS Security Hubでの検知対象

Lambda関数がパブリックアクセス可能な状態であるリソースベースポリシーが過度に許可されている場合、AWS Security Hubの検知対象となります。Security Hubは、このようなセキュリティリスクを自動的に検出し、対応が必要な事項として報告します。

## まとめ

リソースベースポリシーを適切に設定することが大切です。最小権限の原則に基づき、必要最低限のアクセス権限のみを許可しましょう。
CLIやCloudFormationなどを使用してLambdaを作成するときは、リソースベースポリシーを忘れずに作成しましょう。


## 参考
https://docs.aws.amazon.com/securityhub/latest/userguide/lambda-controls.html#lambda-1
https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-lambda-2
CloudFront + S3 でアクセスを特定ドメインからのアクセスに絞りたい

## やりたいこと
- S3にある公開データに対するアクセスを制限し、Botなどによる大量アクセスをはじきたい

## 方法

今回は、CloudFrontとCloudFront関数を利用して作成する。
ざっくり制御なのでもっと良い制御方法があるかも、、？

S3のアクセスをCloudFrontからのみに制御する方法は

https://qiita.com/koinunopochi/items/4ddf2d42f17ee6901315

ここら辺の記事を参考にやってみてください。
本題ではないので割愛します、、、

## アクセス制御する
ここまでできている人はほとんど読む必要がないかもですが、CloudFrontの機能にある関数を利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/3b6c3501-24af-ba7c-a50a-01ac4335869d.png)

関数を作りましょう。

```js
function handler(event) {
    var request = event.request;
    var headers = request.headers;
    
    // Refererをチェック
    var referer = headers.referer ? headers.referer.value : '';
    var pattern = /^https?:\/\/[^\/]*\.hoge\.com\//;
    
    if (!pattern.test(referer)) {
        return {
            statusCode: 403,
            statusDescription: 'Forbidden'
        };
    }
    
    return request;
}
```

ざっくりrefererヘッダが自分のサイトじゃないとだめと、設定しました。
他にもX-Custom-Authヘッダなどを作成して適当なアクセスをはじくでもよいかもです。

:::note warn
注意としては、狙いをつけられると簡単にアクセスされるのであくまでも公開情報に無差別にはアクセスできないように保険を掛ける程度にしてください。
秘密情報は簡単に漏れるので注意です。
:::

## まとめ
本当にアクセスを制御したい場合は、認証認可のシステムを組み込む必要があるので結構面倒かも、、？
内容スカスカのコントリビュートを何というのか


## 1. 初めに

面接などで「私はOSSで有名な○○のコントリビュータです！！！（ﾄﾞﾔｧ…」とアピールするためだけに作る内容スカスカのプルリクのことを何というのか気になった。

## 2. 結論

ググった感じ「スパムPR」が一般的か？

https://github.com/expressjs/express/issues/5449

## 3. 事例

こんな記事を見つけた。
景品のTシャツ目当てで内容スカスカのPRが増えたという内容。

https://gigazine.net/news/20201002-digitalocean-hacktoberfest-hurting-open-source/

## 4. 余談

ちなみに、かつてQiitaでは、タグを追加するだけの編集リクエストを送るスクリプトで恐ろしいほどのコントリを稼ぐアカウントが存在していた。

## 5. チラ裏

CONTRIBUTING.mdがあるならそれに従うのはそうだが、
ない場合もいきなりプルリクを送るのではなくて、まずはissueで相談なりすべきなのでは？と思う。
CloudFormation で生成した Stack が詰まってしまった場合の解決方法

# これなに

- CloudFormation を利用して CLI から Stack を作成して実行したい
- しかし、その時にステータスが処理中系の状態になっており CLI でのコマンド実行が失敗してしまい、処理を止めたい時にどうにかしたいと思ったのでそれの解決方法を調べてみた


# 記事作成の背景

- 以下の通り、該当の Stack 名称がスタックしてしまってエラーが発生したことで本記事作成に至った

```zsh
$ aws cloudformation deploy --template-file 4_cloudformation_db_stack.yml --stack-name su3hokkaido-app --parameter-overrides $(cat dev.cfg) --capabilities CAPABILITY_NAMED_IAM --no-execute-changeset

An error occurred (ValidationError) when calling the CreateChangeSet operation: Stack:arn:aws:cloudformation:ap-northeast-1:314146317837:stack/su3hokkaido-app/2d6a1ab0-a72d-11ef-9c48-06a6ece35625 is in ROLLBACK_COMPLETE state and can not be updated.
$ 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819748/6f8b6a1b-ec72-ffd3-d826-4aa6de8f2f7b.png)


# 解決方法

### 1: Stack を削除する

特になければ一旦はこちらの方法で解決可能。
削除したら CloudFormation の画面で該当の Stack が削除されたことを確認してみましょう。

**実行コマンド**

```zsh
$ aws cloudformation delete-stack --stack-name ${STACK_NAME}
```

**実行例**

```zsh
$ aws cloudformation delete-stack --stack-name su3hokkaido-app
```

### 2: Stack を強制的に削除する

前述の方法がダメならこちらで強制的に削除しましょう

**実行コマンド**

```zsh
# スタックの削除保護を無効にする
$ aws cloudformation update-termination-protection --stack-name ${STACK_NAME} --no-enable-termination-protection

# スタックを削除する
$ aws cloudformation delete-stack --stack-name ${STACK_NAME}

# スタックの削除が完了するまで待つ
$ aws cloudformation wait stack-delete-complete --stack-name ${STACK_NAME}
```

**実行例**

```zsh
$ aws cloudformation update-termination-protection --stack-name su3hokkaido-app --no-enable-termination-protection
$ aws cloudformation delete-stack --stack-name su3hokkaido-app
$ aws cloudformation wait stack-delete-complete --stack-name su3hokkaido-app
```

# あとがき

GUI も便利ですが CLI から実行した方が理解を深めることができるので、ガイドを参考にしながら学習を進めたい…

https://docs.aws.amazon.com/cli/latest/reference/cloudformation/delete-stack.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819748/590b08b5-f9c5-ca60-644d-af4170db6951.png)
PowerAutomateで個人用OneDrive内のExcelファイルの編集ができなかった話

今まで自動化ツールを使用したことがほとんどなかったので、PowerAutomateを試してみたのですが、
実行できるまでに思っていた以上に時間がかかってしまったので、
反省として書き残しておきます。
## 原因
OneDriveがビジネス版でなかったため、PowerAutomateからExcelファイルの操作が行うことができなかった。

そもそもPowerAutomate以前の問題だったのですが、これが分かりませんでした。

## PowerAutoMateについて
PowerAutomateは、Microsoftが提供する自動化プラットフォームです。
Microsoftのアカウントがあれば、ある程度の機能は無料で使用でき、
Webアプリなのでインストールも不要で、既に使用しているGmailやOneDriveとの連携もできるので、手軽に始められると考え今回試してみました。

## 実装内容
作成しようとした処理の流れは、
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3128258/463771cf-bdd0-ab6c-ecd6-056272f9af9c.png)

①Gmail受信で処理を実行
②OneDrive上のExcelファイル内のテーブルに受診したメールの件名と受診時刻をそれぞれ追記

これだけです。
 
フロー作成後の画面右上のフローチェッカーでも問題なく、テスト処理から手動で実行しても動作したので、作成時点ではこれで問題ないと思いました。
 
しかし実際に自動処理として実行されると以下のエラーが発生しました。

![error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3128258/c701e05a-73a2-6617-b684-8c955dc66b5c.png)

エラーメッセージにはpermissionsと表示されているので権限周りに問題があるのかと思い、Excelファイルのアクセス権を確認しましたがそちらは問題なく、原因がわからないまま調査を続けていきました。

最終的に見つけたのはMicroSoft公式の以下のページで、
OneDriveでのExcel操作については、個人用OneDriveの場合、Webアプリケーションでの操作はサポート対象外になるとありました。

https://learn.microsoft.com/ja-jp/graph/api/resources/excel?view=graph-rest-1.0
「注: OneDrive のコンシューマー向けのプラットフォームに保存されたブックは、サポートされていません。」

Excelではなくテキストファイルに書き込みを行うようにしてみたところ
問題なく動作するようになりました。 
 ![text.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3128258/fd07a353-6439-c5f6-7457-7b3073d6b333.png)

![success.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3128258/f5ad53ac-2bc3-47ee-5504-00d35f163555.png)

## まとめ
OneDrive側のExcelの仕様について調べればすぐに原因が分かったことですが、
OneDriveについては以前から個人用で使っていたので、ビジネス版との違いについての考えが完全に抜けており、新しく始めたAutomateの方に問題があると思い込んでいたため、調査に時間がかかってしまいました。

アプリ間での連携時には使い慣れたアプリでも、仕様は改めて確認しないといけないと実感しました。
Python sklearn,NearestNeighborsでレコメンド（アイテムベース）

## ■完成出力
・対象データが movieId が２の場合の出力
![完成出力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478380/73379b75-fd9a-e30f-dc2c-ca2e73487f48.png)

### ・データ例
・movieId 364のカラム列
![レコメンドデータ01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478380/a8f9d6fc-791b-68ec-f451-9870a212e751.png)

### ■ソースコード
```item.py
import pandas as pd
from sklearn.neighbors import NearestNeighbors
import numpy as np

###=============  アイテムベースでレコメンド =============###

# 読み込み
df = pd.read_csv("ml-latest-small/ratings.csv")

# 先頭出力
# print(df.head())

# 疎行列（ほとんどの要素が 0 の行列）
# アイテム/ユーザ行列

#pandas ピボット
df_rating = df.pivot(index="movieId", columns="userId" ,values="rating").fillna(0)
# print(df_rating.head())

###### 最近傍探索
neigh = NearestNeighbors(metric="cosine")

# **************************************
# ****** 学習する *******
# **************************************
neigh.fit(df_rating)


# ★★★★★★　特定の映画に近いものを探索　★★★★★★
# movieId2 に近いもの
distanve, indices = neigh.kneighbors(df_rating[df_rating.index == 2])

# [[  1 322 436 325 418]] 2次元のindex
print(indices)

# ↑　１次元にする
print(indices.flatten())

# 出力

for i in indices.flatten() :
    print(df_rating.index[i])

### 出力 結果
# 2
# 364
# 500
# 367
# 480

```
【AWS】Lambdaで「No module named 'pydantic_core._pydantic_core'」エラーに遭遇した場合

# 概要
AWS LambdaでPythonコードを実装していたら以下のエラーに遭遇しました。

> [ERROR] Runtime.ImportModuleError: Unable to import module 'app.main': No module named 'pydantic_core._pydantic_core'

こちらの原因と解決方法を紹介します。

# 前提と原因
まず、前提として、AWS Lambdaでライブラリを動かす場合は、ローカル環境でライブラリをzipにパッケージ化してLambda Layerにアップロードする必要があります。ただし、このパッケージ化する環境によっては、Lambda側の環境と異なるアーキテクチャになることがあり、それが原因でエラーになることがあります。

例えば、私のローカルマシンを`uname -a`すると以下のように表示されます。

> Darwin xxxxxxMBP 21.6.0 Darwin Kernel Version 21.6.0: Mon Aug 22 20:19:52 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T6000 arm64

arm64とありますね。
そして、原因はまさしくここにありました。

Lambdaでは、アーキテクチャの選択肢としてarm64とx86_64が選べます。
ここでx86_64を選択したLambdaに、arm64でパッケージ化したzipをアップロードすると冒頭の以下のエラーになりました。

> [ERROR] Runtime.ImportModuleError: Unable to import module 'app.main': No module named 'pydantic_core._pydantic_core'

これは、AWS Lambda関数がx86_64アーキテクチャで設定されておりarm64用のバイナリは互換性がないため、モジュールが見つからないエラーが発生しているのです。

## 解決方法
ネットを調べていると、dockerfileを利用する方法、Cloudshellの環境を利用する方法、アプリと同階層に`python`ディレクトリで配置する方法など、色々ありました。

ただ、私はいずれも成功できなかった（or正しく試せていない）ので、あくまで私のケースでは解決できた方法を紹介します。

それがAWS公式ドキュメントにも記載のある以下のスクリプトです。

https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-native-libraries

（参考：以下の記事でも同様に対処している）

https://zenn.dev/tnakano/articles/036a1b87082296）


```sh
mkdir python

pip install \
--platform manylinux2014_aarch64 \
--target=python/python/lib/python3.12/site-packages/ \
--implementation cp \
--python-version 3.12 \
--only-binary=:all: \
--upgrade \
--no-deps \
-r requirements.txt

cd python

zip -r ../fastapi-layer.zip .

cd ..

rm -rf python
 ```

 AWSドキュメントから一部変更してあります。
`--only-binary=:all: --upgrade`だと、mysqlclientインストール時に以下のエラーのなりました。

> ERROR: Could not find a version that satisfies the requirement mysqlclient (from versions: none) ERROR: No matching distribution found for mysqlclient

mysqlclientは特定のplatform用に事前にコンパイルされたバイナリが必要らしく、上記スクリプトのように少し改変したのはそのための処置です。

`--no-deps`オプションを指定すると、依存関係を無視して指定されたパッケージのみをインストールできました。

> --no-deps
Don’t install package dependencies.

https://pip.pypa.io/en/stable/cli/pip_install/

私上記のようにインストールの上、Lambda側もarm64にしてアップロードすると正常に動作するようになりました。
NGINXでリクエストヘッダーをログに記録する方法

NGINXでリクエストヘッダーをログに出力するには、カスタムログフォーマットを設定し、特定のリクエストヘッダーをログに含めるように設定します。以下に手順を説明します。

---

### 手順

#### 1. `nginx.conf` にカスタムログフォーマットを追加

`nginx.conf` ファイルを編集して、`log_format` ディレクティブでカスタムフォーマットを定義します。例として、`X-Custom-Header` ヘッダーをログに記録する場合は次のように設定します。

```nginx
http { log_format custom '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_x_custom_header" "$http_user_agent"'; access_log /var/log/nginx/access.log custom; }
```

‌

- `$http_x_custom_header`: リクエストヘッダー `X-Custom-Header` の値を取得します。
- 他のヘッダーを記録したい場合は、`$http_ヘッダー名` の形式で記述します（ヘッダー名は小文字で記述し、ハイフンはアンダースコア `_` に置き換えます）。

---

#### 2. サーバーブロックでログフォーマットを有効化

すべてのサーバーブロックまたは特定のサーバーブロックに以下を追加します。

```nginx
server {
  ...
  access_log /var/log/nginx/access.log custom;
  ...
}
```

---

#### 3. NGINX をリロード

設定を保存したら、以下のコマンドでNGINXを再読み込みします。

```nginx
sudo nginx -t # 設定ファイルのテスト
sudo systemctl reload nginx # NGINXを再読み込み
```

---

### 例: ログ出力の例

例えば、リクエストヘッダーに以下が含まれていた場合:

```
X-Custom-Header: TestValue User-Agent: curl/7.68.0
```

‌

ログには次のように出力されます:

```
127.0.0.1 - - [20/Nov/2024:12:34:56 +0000] "GET / HTTP/1.1" 200 612 "TestValue" "curl/7.68.0"
```

‌

---

### 注意点

1. **セキュリティ**: ログにセンシティブな情報（認証トークンやパスワードなど）を含めないよう注意してください。
2. **ログの管理**: ヘッダーを多く記録するとログが膨大になる可能性があるため、ログローテーションやストレージの管理も考慮してください。

必要に応じて他のヘッダーもログに出力できるよう設定を拡張してください。
揺れものってどうするの？

たまに見かけるんですが、揺れものリグってどうやるんですか？って質問。
毎回おんなじ様な事答えてるので一回自分の考えをまとめてみます。

もちろん他にも良い方法は沢山あると思うので、お勧めの方法あれば是非ご教授ください


# 揺れもの　の定義

揺れもの　揺れものとありますが、具体的にはどんなものがあるかというと

- 髪の毛
- 上着の裾
- マフラー
- マント
- 脂肪
- 鎖

などなど、色々とあります。

これらの動きを付ける方法ですが、
**だれが、どのタイミングで、どうやって動きをつける**のかによって色々と変わってきます。


# 揺らす方法

凄く雑に分けると

- **手付け**
- **シミュレーション**

の2択になると思います。

手付けに関しては

**アニメーターさんが**
**アニメーション作業時に**
**キーフレームを設定して動きをつける**

訳ですね。

ではシミュレーションに関してはどうでしょうか？

# シミュレーションの種類

シミュレーションももう少し細かく分類できます。

## リアルタイム

ゲームなどのエンジン上で、動的に揺れる動きをつけてしまうタイプ
この辺は詳しく知らないのですが、

KawaiiPhysics　とかよく耳にします。

https://github.com/pafuhana1213/KawaiiPhysics


## キャッシュ作成

映像作品フル３D作品や実写映画のVFXなどではDCCツール上で、
完成したアニメーションにあわせて揺れものの物理シミュレーションを行い、
再計算の必要が無いように結果をキャッシュとして保存しレンダリングにまわします。

この場合シミュレーションを行うのは、**専門部署** だったり **リガー**　だったりと組織によりますね。

シミュレーションを行うツールは **Maya**だったり、**Hudini**だったり、**マーベラスデザイナー**だったり、これも組織によりますね。


## リグ組み込み型

おそらくよく見かける質問をしてる方々はこれが主流だと考えてるのかなと。
あらかじめ揺れもの部分にシミュレーションできるセットアップをリグに組み込んでおいて、
アニメーターさんがアニメーション作業中にそれを使って動きをつけられるようにしておく方法ですね。

ものにもよりますが、nHairを使ったものはたまに見かけます。
セットアップの方法については　バックボーンスタジオさんのブログでも紹介されてますね。

https://backbone-studio.com/blog-nhairrig/

ただこの手法の場合、動きが確定した際にどうするかが重要になってきます。
確定しても　再現できない　or 再現するのに再計算が必要なので時間がかかる　だと困る人が多いです。

なので、キャッシュを作成するなりベイクするなりして動きをFIXさせる訳ですが、
これは組織のパイプラインに依存してくるかなと思います。

自分はこの方法嫌いなので、やらないです。

## 後乗せタイプ

既存のリグに作業シーン内でシミュレーション機構を一時的に被せてシミュレーションを行い、
結果をコントローラーにベイクしてキーフレーム化する　というタイプですね。

ツール化されてることが多く、内製ツールだったりフリーのツールだったりします。

Mayaだとフリーのものが幾つかありますね。

例)

Spring Magic in Maya

https://animbai.com/2017/10/28/spring-magic/comment-page-2/

最近だとプラグインを作成されてる方もいますね。こちらを使用すればnHair使わずにリグに組み込んだり、後のせできますね。

boneDynamicsNode

https://github.com/akasaki1211/boneDynamicsNode


※完全に偏見なのですが、この手法についてはフル３D作品のアニメーターさんの方が存在を知ってることが多く、アニメ系のアニメーターさんには知られてないのかなぁという印象があります。

※以前似たようなツールを作った時には　これは何の役に立つの？手で揺らせばいいじゃん。　って言われたことがあるので、まぁ文化の違いなんだろうなと。


## 永久になびく

これはシミュレーションではないのですが、
旗・マフラー・マント　などで　待機モーションや風がふきつけてるときなど
ずーっとなびき続けている場合には、 
スイッチを入れてばなびき続けるようなセットアップをsineデフォーマーやなんやかんやを使ってリグに組むことがあります。


# で、結局？

で、結局のところ

**作品のテイスト**
**組織の構造**
**パイプライン**

等々のオプションによって

**だれが、どのタイミングで、どうやって動きをつける**べきなのかが決まってくるので、
一概に**この手法が正解**なんでことは無いと思います。

ただし、手法の選択肢が複数あることで↑のオプションそのものを変える事ができるので色んな手法を知っていて損はないかなと。
Vueを使う時はコンポーネントの無限ループに注意しよう！

こんばんは。
[前回](https://qiita.com/Odashikonbu/items/4f5756def7b881a83a05)の記事であれだけSolidJSを褒めちぎっておいてアレですが、
結局Vue.jsでTauriのツール開発を続けています。

なんだかんだ言いましても仮想DOMはWEBアプリ成長期から現在に至るまで世界中のWEBを支え続けてきた技術ですから。
「仮想DOMレスの技術が出てきたのでお払い箱」と切って捨てるのはあまりにも不誠実だと思い直しまして、
改めて画面のパフォーマンスに考慮した仮想DOMフレームワークの書き方を考えてみました。
~~VueとかReactの方が圧倒的にお金になる案件多いしね~~

前回Vueを使ったときに悩まされた画面フリーズの問題についても原因の切り分けと対策を確立しましたので、軽くここで説明させていただきます。

### コンポーネントがフリーズする原因を切り分けてみた。
細かい部分を全部すっ飛ばして極限まで簡略化すると、Vueの基本構成は以下のような感じになると思います。
親コンポーネントから子コンポーネントを呼び出し、設定したいパラメーター等をpropsで渡す。
コンポーネントの垣根を越えて値を共有したい場合は外部でrefを宣言してexportしたり、
useStateやpiniaの状態管理機能でグローバル値を定義するイメージです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923046/9449ccbb-7883-831b-83e3-c86d5b5b7397.png" width=50%>

この中で画面フリーズを引き起こす最大の原因はグローバル値です。

例えば、下記のような形式で親と子のコンポーネントで同じrefを共有したとしましょう。

```typescript:state.ts
import { ref } from "vue";

export const state = ref<string[]>(["りんご", "バナナ", "みかん"])

```

```vue:oya.vue
<script lang="ts" setup>
  import { state } from "./state";
  import Ko from "./Ko.vue"

  state.value.forEach((item) => {
    item = item + "ジュース"
  })
</script>

<template>
  <Ko v-for="item in state" :item="item"/>
</template>
```
```vue:Ko.vue
<script lang="ts" setup>
  import { state } from "./state";
  const props = defineProps({
    item: String
  })

  const addItem = ["ぶどう", "スイカ", "いちご"]
  addItem.forEach((item) => {
    state.value.push(item)
  })

</script>

<template>
  <h1>{{ props.item }}</h1>
</template>
```

子と親、両方でグローバルrefのstateに要素を追加し合っていますね。
これだけでもうTauri上ではフリーズしたような状態になりまともに動作しなくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923046/f2bd6cf4-9079-fe8b-2c85-78d196f3149c.png)


アプリは真っ白のまま、devtoolも一切状態をキャッチしてくれません。

### 何故こうなるのか

原因を簡単に説明します。
仮想DOMはコンポーネントを構成している要素の変更を検出すると、自動でキャッシュされている変更前の状態と変更後の状態を比較し、その差分を検出します。
変更部分だけを仮想DOM上で変更し、変更した仮想DOMを画面に適用することで高速な画面描画の変更を可能にしているわけです。

ここで気を付けなければいけないのは、差分検出と画面の再描画が行われるたび、描画されたコンポーネント内のscript処理が繰り返し実行されてしまうということ。

例題のコードでは子コンポーネントからグローバル配列に対し["ぶどう", "スイカ", "いちご"]をpushしていますが、グローバル配列の各要素は子コンポーネントを構成しているpropsでもあります。

propsが入った配列に要素が追加されると、当然子コンポーネントは再描画されます。
再描画されるたび配列に対して["ぶどう", "スイカ", "いちご"]を追加し続ける、所謂「無限ループ」のような状態になってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3923046/469629f9-24c8-cf9e-d5db-1904f989dbaa.png)

### どうやって防ぐのか

- 子コンポーネントでpropsの構成要素に触らない。

これだけです。
どうしてもグローバル値をpropsとして使用したい場合は別の配列に格納して固定値化するか、子コンポーネント内からグローバル値への参照を消してしまいましょう。
API設計の基本：エンドポイントとレスポンスの考え方

この記事では、API設計におけるエンドポイントとレスポンスの基本的な考え方をまとめます。短く、わかりやすく、そして統一感のあるAPIを設計するためのヒントを具体例とともに素人が本で学んだことを一部解説します。


## エンドポイント設計
エンドポイント（APIにアクセスするためのURI）の設計は、APIの使いやすさを以下のルールを守ることで、直感的で保守性の高いAPIを作ることができます。

### 1　URIの基本設計
#### ・短く入力しやすいURI
読んで字のごとくのことです。シンプルで覚えやすいことです。
意味が重複しないようにすることが大事

例
```
/users  # ユーザー関連の操作
/tasks  # ToDoリスト関連の操作
```

#### ・人が読んで理解できるURI
これは省略した文字や日本語で書かないように世界共通の英単語を使うのがもっとも一般的ということ
利用する英単語でも「find」と「search」など似たような意味があったりするのできちんと調べて使い分けるようにする
メソッドで使い分けるとわかりやすい
例
```
POST /tasks          # 新しいtaskを作成
GET /tasks           # 全てのtaskを取得
PUT /tasks/{id}      # taskを更新
DELETE /tasks/{id}   # taskを削除
```

小文字で統一するために複数の単語が並ぶときはハイフン（ー）を使うスパイナルケース（ケバブケース）利用する
```
/to-do-items  # 視認性が良い
```
もちろん既存のルールに統一するのがわかりやすい


#### ・複数形を基本とする
例
```
/users  # 良い例
/user   # 一貫性がないため避ける
```

## 2.レスポンス設計
レスポンスではできるだけ短い単語を使い直感的に内容を理解できるように設計する

### JSON形式と基本設計
APIレスポンスをJSON形式で記述することは、現代のWeb API設計において最も一般的な方法です。JSONはシンプルで軽量なデータ形式であり、データの構造が明確で、さまざまなプラットフォームで簡単に利用できるため、多くのメリットがあります。

#### ・JSON形式とキャメルケース
JSON形式のレスポンスで複数の単語を扱う場合はキャメルケースを採用

例
```
{
  "userId": 1,
  "userName": "Taro Yamada",
  "email": "taro.yamada@example.com"
}
```

複数のレスポンスがある場合は短いのがオブジェクトで包むことを
推奨していました。

例
```
{
  "tasks": [
    {
      "id": 1,
      "title": "買い物",
      "isCompleted": false
    },
    {
      "id": 2,
      "title": "運動",
      "isCompleted": true
    }
  ]
}
```

### ステータスコードの分類

レスポンス内容を理解しやすくする重要な要素
以下に主なステータスコードをカテゴリ別に整理して役割と使用例を示します

100番台 情報
200番台 成功
300番台 リダイレクト
400番台 クライアントサイドに起因するエラー
500番台 サーバサイドに起因するエラー



APIのことはまだ奥が深いですがとりあえず基本のみを書いていきました。
本にも書いてましたが作者が勧めている基本であって既存のルールに統一するのが一番だと思っています。
AWS MLS合格(更新)記(2024/11/20投稿)

# はじめに
この度AWSのAWS Certified Machine Learning – Specialty認定試験を受験してきましたので、勉強した内容と受験した感想を書いておきます。
今回は更新目的の受験になります。

前回は2022年1月に受験していました。

https://qiita.com/handy-dd18/items/42ae7b81851658ee3187

# 前提
* AWSのデータ周りのサービスは過去に業務で扱ってました
* 機械学習周りはSageMakerの一部機能を触ったことがある程度で、あとは他のクラウドの認定試験を受験する際に学習した知識のみ
* AWS認定は全て取っています(詳細は[こちら](https://qiita.com/handy-dd18/items/d21d914bf1c475d777f2))
    * PASは[こちら](https://qiita.com/handy-dd18/items/18e8a856906f97bbb964)
    * DEAは[こちら](https://qiita.com/handy-dd18/items/cd9410fc2c02a28b4c1d)
    * AIFは[こちら](https://qiita.com/handy-dd18/items/724c67c7b2fa63e2ea89)
    * MLAは[こちら](https://qiita.com/handy-dd18/items/d4763f4afdbf7b0a818b)
* AZ-900/DP-900/AI-900/AZ-104/AZ-204/AZ-700/AZ-305/AZ-500/DP-203は取得済み
* Google Cloud認定はMLとWorkspaceを除いた9つ取ってます

# 学習内容
今回は更新ということと直近で出たAWS認定の新試験([AIF](https://qiita.com/handy-dd18/items/724c67c7b2fa63e2ea89),[MLA](https://qiita.com/handy-dd18/items/d4763f4afdbf7b0a818b))を取得していたので、以下の模擬問題だけを受講して試験に臨みました。

* [①Udemy模擬問題](https://www.udemy.com/course/aws-30-b/?couponCode=KEEPLEARNING)

## ①Udemy
購入したUdemyの模擬試験講座は以下になります。

- [【最短攻略】AWS 認定機械学習 – 専門知識 模擬問題集](https://www.udemy.com/course/aws-30-b/?couponCode=KEEPLEARNING)

演習テストが2つあり、それプラス「機械学習用語確認セット」という演習テスト(32問、120分)が付いていました。
今回も他の更新試験同様にあまり勉強時間を取れなかったので、演習テスト1のみを解いて間違えた問題の解説を読み込むところまでを行いました。


Udemyの模擬問題の内容ですが、概ね本番と似た形式の問題が多かったのではないかと思いました。
ただ私がMLS勉強するのがかなり久しぶりだったので、機械学習の手法やモデルの評価方法などのAWS以外の部分の知識がかなり忘れていたので、そのあたりを重点的に覚え直しました。
AWS側の知識(SageMakerなど)はMLA試験のために学習したものが割と役に立ったので、これから受験するという人はMLA→MLSで受けるとある程度流用できると思います。


あとは当たり前ですが、以下のような評価指標などは頻出するので覚えておく必要があります。(自分は一部うろ覚えで臨んだので思い出すのが大変でした)
```
- 正解率・正確さ： （TP + TN） / （TP + FP + FN + TN）
- 精度：TP / （TP + FP）
- 再現率・真陽性率：TP / （TP + FN）
- 真陰性率：TN / （FP + TN）
- 偽陰性率：FN / （TP + FN）
- 偽陽性率：FP / （FP + TN）
```

Udemyではそのあたりの理由まで解説されていたので、解説を読んで理解→理解しきれないものは追加で調べて学習、という流れで勉強するのが良いかと思います。


# 受験した感想
一部Udemyの模擬試験と類似した出題傾向の問題は出ましたが、半分以上は初見の問題が多かったです。
MLSは全部で65問あり、10問ずつ大体15～20分ぐらいのスピードで解いていき、全て解き終わった頃には見直しフラグ38問、試験時間は60分ぐらい残っている状態でした。

私の普段の試験戦略として、**まずは一部適当でも良いので全ての問題に解答して、フラグを付けた問題を時間を掛けて解いていく方法**をとっているため、今回も同様のやり方をしました。
自分が即答できない問題や問題文が長くて時間がかかる問題はなまじ残り時間に余裕があるように見えてしまって、読み解いて正答を考えるのにダラダラと時間を消費してしまいがちなので、残り時間を敢えて少ない状態で取りかかることで集中力を維持するようにしています。

内容には言及できないので書けませんが、やはりAIFやMLAと同じで試験ガイドの内容をどれだけ理解しているかが重要だと思いました。


# 受験結果
結果としては795点で合格しました。結構ギリギリだと思っていたので思ったよりも点数取れていたのには驚きでした。
![1000015604.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/47be5604-6d13-98e1-7980-81fc49484deb.png)


# おわりに
MLSの更新期限は2025年1月でしたが、無事更新できて安心しました。
来週はSAProの更新試験なので気が重いですが、また終わったら勉強方法などをまとめたいと思います。

この記事がどなたかの参考になれば幸いです。
【Sier,情シス向け】ネットワークエンジニアに知って欲しい自動化技術

# ネットワークエンジニアの悩み
- 100n台分の機器からshowコマンド取得しないといけない。。(量産)
- 100n台分の機器へ設定を投入しないといけない。。(量産)
- 詳細設計書(パラシ)100n枚作る/更新しないといけない。。(量産)
- 投入コンフィグ100n枚作らないといけない！？（気絶）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899867/f049a34d-05a9-8965-da93-6faa3f6ad901.png)

=> ポート表も一定パターンがあれば展開は楽なのですが、クラウド基盤で大量のサーバ向けToRが対象で～といったお仕事でないとそうもいかないのが実情です。
=> これ、自動化しませんか？という話題です。

比較的簡単に実装できるものもあれば難易度が高いものもあるので、事例と共にご紹介できればと思います！有償製品を用いるのではなく、全てフリーで実現可能です。

注意：本自動化記事ではCisco Systems製品の自動化に視点を絞っています。

## 自己紹介(2024/12時点)
- 独立系Sierでネットワークの設計構築やってます。
- 詳細設計書作成更新、機器作業の自動化実績があります。

## 実現難易度・イメージ
#### showコマンド取得・設定投入自動化
★☆☆☆☆＜やろうと思えばほぼ誰でも直ぐに実現可能＞
=>Ciscoで開発され現在は一部オープンソースのソフトウェア"pyATS"を用いて自動化可能です。無料です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899867/43d49a2b-7e6d-3ebc-4649-d5130cb7641a.png)

#### 投入コンフィグ作成自動化
★★★☆☆＜Pythonの知識が必要＞
=>Pythonで元となる詳細設計書や資料の情報を辞書なりjsonなりで吸い出してjinja2というテンプレートエンジンからテキストファイルへ出力するという流れになります。全てがPythonなので、至る所に分岐処理等差し込めます。柔軟なテンプレート設計が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899867/8fbe101b-85e8-cd99-1a7c-92ce6d25e6a2.png)


#### 詳細設計書作成更新自動化
★★★★★＜Pythonの高いスキルが必要＞
=>ざっくり以下のようなステップを踏む必要があります。最低でもトータル1000行位はコード書かないといけないので、結構大変です。
①機器のコンフィグファイルをPython3で読み込んで詳細設計書に落とし込みたい設定情報を辞書なりjsonなりで加工,保存
②自動化台数分Excelのテンプレシートを展開(Pythonでテンプレ自体を定義・出力してしまうパターンと、テンプレだけExcelで作成するパターンで二つオプションがあります)
③各機器の設定情報をテンプレ展開済みのExcelシートへ書き込み
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899867/d923b2a3-86f0-92be-79f0-9f1f5a649bf1.png)

=> 実装してしまえば以降の追加機器向けシート作成作業や、更新作業は不要になります。人間が更新情報を追わずに済むうえにレイアウト雑問題も解消(罫線が一部セルで抜けてたりとか..)できるので、品質が段違いに上がります。また、チェックも全量ではなく"パターンベース","コードベース"で行えるので圧倒的に楽です。
Si現場あるあるの"資料更新が追いついておらず全くアテにならない資料化"はこれで防ぐことができます。


## 各自動化詳細記事
#### showコマンド取得・設定投入自動化

https://qiita.com/satani/items/7f03a34f218be63ded17

#### 投入コンフィグ作成自動化
鋭意制作中
#### 詳細設計書作成更新自動化
鋭意制作中

## 免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、所属する組織の意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、投稿者が所属する組織や他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任から投稿者の所属する組織を免責することに同意したものとします。
TouchDesignerのライセンスドングルのアップデート

私はUSBドングルでライセンスを利用しているのですが、更新しようとしたときに躓いたのでメモとして残します。  

ちゃんと公式マニュアルに書いてあるのですが、最初は読んでいなかったので。。

この記事がすぐに役立つ人はそんなにいないと思うので、以下のことだけを頭の片隅に入れておいてください。

- アップデートライセンスを購入した後、Derivativeにメールを送り、更新用のリンクを貰う必要がある
- 今日すぐにドングルのライセンスをアップデートしたいと思ってもメールの往復で1~2日かかる可能性がある


そもそもTDのライセンスとは？という方は、[こちらの解説](https://scottallen.ws/iamas/de2021_0_install#%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9)が分かりやすいです。


## 公式マニュアル
https://derivative.ca/UserGuide/License_Dongle


## 手順1 ライセンスを買う

Derivativeのサイトにログインし、MY LICENSESからアップデートしたいライセンスを選択し、PURCHASE UPDATEを押して手続きを進めます。  
完了するとEmailで購入完了のお知らせが届きます。  

![license.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/409de778-bae0-7752-ef18-4c1e134465c6.png)


## 手順2 メールを送る(ここ重要！)

公式マニュアルには以下のように記載されています。

```
email your dongle number or license ID to licensing@derivative.ca to request an Activation Link. 
```

ということで、MY LICENSESの情報を記載してメールを送ります。  
営業日にもよると思いますが、私の場合は週末だったので週明けに返信があり、アクティベーション用のリンクを受領しました。  


## 手順3 ライセンスをアクティベートする

PCにドングルを刺した状態で受領したリンクを開きます。  
アクティベートを行う を押すと、ライセンスの更新が完了します。  

![licence_update.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/8f4d126f-1561-6b62-e132-5dc9753d13bb.png)

![licence_update2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/5492353b-d691-91d9-d222-7481ef263454.png)


# おわりに
300$が4万5千円なのはヘビーですね。  

ライセンス更新したので使う機会をお待ちしています :)
Azure OpenAI で o1モデル のAPIを使う方法

# はじめに
Azure OpenAIでo1モデルのAPIが使えるようになったので、その方法についてまとめます。
なお、利用にあたり必要な申請は済んでいることとし、APIキーも取得済とします。

使い始める方法は以下などを参考にしてください。
https://zenn.dev/headwaters/articles/e7cd59c54b23a5

# 方法
基本的には[以前まとめた方法](https://qiita.com/yujimats/items/a424f608653c74348bcd)と同じです。
## モデルのデプロイ
Azure内のOpenAIリソースにて、o1-previewまたはo1-miniをデプロイします。
`API_key`、`API_ENDPOINT`, `OPENAI_MODEL`を確認し、環境変数などの登録します。

## Langchain
以下のように設定すれば利用可能です。
```python
from langchain_openai import AzureChatOpenAI

def get_models(temperature=1.0) -> AzureChatOpenAI:
    llm = AzureChatOpenAI(
            api_version=2024-02-15-preview,
            azure_endpoint=API_ENDPOINT,
            api_key=API_KEYS,
            azure_deployment=OPENAI_MODEL,
            max_tokens=max_tokens,
            temperature=temperature
        )
        return llm
```

## 注意点
注意点として、LLMのパラメータである`temperature`は`1.0`以外はサポート対象外だそうです。
それ以外の値をいれるとエラーが出るので、注意してください。
ddclientでCloudflareのDNSを更新しようとしたときにハマった話

CloudflareでDNS管理をしていますが、固定IPでない自宅インターネット環境をDNSに登録したくて、ddclientを使ってDNSレコードを更新しようとしたところ、すんなりと行かなかったので顛末を記録します。
なおddclientのインストール方法とCloudflareでAPIトークンを発行する手順についてはこちらでは説明いたしません。

# CloudflareのアカウントをGoogleアカウントで登録していた

Cloudflareのアカウントを作成する場合、メールアドレスで作成する方法と、GoogleアカウントまたはAppleアカウントで登録する方法があります。
私は、メールアドレスではなくGoogleアカウントで登録をしていました。

# Cloudflareが示した認証情報

ddclientをセットアップする際に求められる情報として、メールアドレスとAPIトークンがあります。
しかしAPIトークンを発行したとき、確認用URLとして示されたのが以下のようなコマンドでした。
```bash
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify"
     -H "Authorization: Bearer 1234567893feefc5f0q5000bfo0c38d90bbeb"
     -H "Content-Type:application/json"
```
認証情報にメールアドレスがなく、代わりにBearerトークンが表示されてますね。

# ddclientの動作確認

ddclientの設定を行うにあたり、最初は以下のような設定を記入しておりました。
```
$ sudo vi /etc/ddclient.conf
login=<Googleアカウントに紐づいてるメールアドレス> \
password=<APIキー> \
※前後省略
```
これで動作確認をしてみてるんですが、全くうまく動きません。
`-v`を付けてログを見てみた結果を抜粋します。
`400 Bad Request`が返ってきてますね。なんだか認証に使う情報がマッチしてないように見えます。
```
UPDATE:   updating example.com
DEBUG:    proxy  =
DEBUG:    url    = https://api.cloudflare.com/client/v4/zones?name=example.com
DEBUG:    server = api.cloudflare.com
CONNECTED:  using SSL
SENDING:  GET /client/v4/zones?name=example.com HTTP/1.0
SENDING:   Host: api.cloudflare.com
SENDING:   User-Agent: ddclient/3.9.1
SENDING:   Connection: close
SENDING:   X-Auth-Email: example@gmail.com
SENDING:   X-Auth-Key: 1234567893feefc5f0q5000bfo0c38d90bbeb
SENDING:   Content-Type: application/json
SENDING:
RECEIVE:  HTTP/1.1 400 Bad Request
```

# 対処法

こちらについて、結論から申しますとddclientのプログラムとコンフィグの書き方を変更する必要がありました。

```diff_perl
$ sudo vi /usr/sbin/ddclient
4643行目付近
-                my $headers = "X-Auth-Email: $config{$key}{'login'}\n";
-                $headers .= "X-Auth-Key: $config{$key}{'password'}\n";
-                $headers .= "Content-Type: application/json";
+                my $headers = "Content-Type: application/json\n";
+                if ($config{$key}{'login'} eq 'token') {
+                   $headers .= "Authorization: Bearer $config{$key}{'password'}";
+                } else {
+                   $headers .= "X-Auth-Email: $config{$key}{'login'}\n";
+                   $headers .= "X-Auth-Key: $config{$key}{'password'}";
+                }
```

```
$ sudo vi /etc/ddclient.conf
login=token \
password=<APIキー> \
※前後省略
```

これで改めてddclientを実行してみます。
今度は`200 OK`が返ってきて、無事にDNSの更新が行われました。
```
UPDATE:   updating example.com
DEBUG:    proxy  =
DEBUG:    url    = https://api.cloudflare.com/client/v4/zones?name=example.com
DEBUG:    server = api.cloudflare.com
CONNECT:  api.cloudflare.com
CONNECTED:  using SSL
SENDING:  GET /client/v4/zones?name=example.com HTTP/1.0
SENDING:   Host: api.cloudflare.com
SENDING:   User-Agent: ddclient/3.9.1
SENDING:   Connection: close
SENDING:   Content-Type: application/json
SENDING:   Authorization: Bearer 1234567893feefc5f0q5000bfo0c38d90bbeb
SENDING:
RECEIVE:  HTTP/1.1 200 OK
```

# 参考

https://medium.com/@timothy.halim/ddclient-cloudflare-setup-in-ubuntu-e271c53d3ce8
【Next.js】無駄なレンダリングを簡単に見つける方法

React Scanを使用すると無駄なレンダリングを簡単に見つけられます。

https://github.com/aidenybai/react-scan

## インストール

Next.jsのApp Routerに導入するには `app/layout.tsx` を以下のように記述します。

```tsx:app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ja">
      <head>
        <script src="https://unpkg.com/react-scan/dist/auto.global.js" async />
        {/* 他の script */}
      </head>
      <body>{children}</body>
    </html>
  )
}

```

## 使用方法

ブラウザで動作確認をするとレンダリングされた箇所が強調表示されます。
無駄にレンダリングされている場合にはコンポーネント名の前に `🔥` が表示されます。

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/5fb5d340-7634-5eae-b604-1c3929d030f2.gif)