OmniAICreator/Qiita-1.07M huggingface dataset:
GKE ingressでEmpty reply from serverが出たとき

# 何が起きたか
GKEにingressをデプロイし、IPアドレスがアサインされた後、curlでリクエストを送ったところ、エラーが発生した。
```
% k describe ingress my-ingress
Name:             my-ingress
Labels:           <none>
Namespace:        default
Address:          34.98.64.104
Ingress Class:    <none>
Default backend:  <default>
Rules:
  Host        Path  Backends
  ----        ----  --------
  *           
              /*   nginx:80 (<none>)
Annotations:  ingress.kubernetes.io/backends:
                {"k8s1-150937ce-default-nginx-80-497f3411":"Unknown","k8s1-150937ce-kube-system-default-http-backend-80-615fa400":"HEALTHY"}
              ingress.kubernetes.io/forwarding-rule: k8s2-fr-wyu1g3bu-default-my-ingress-etd1ul6o
              ingress.kubernetes.io/target-proxy: k8s2-tp-wyu1g3bu-default-my-ingress-etd1ul6o
              ingress.kubernetes.io/url-map: k8s2-um-wyu1g3bu-default-my-ingress-etd1ul6o
Events:
  Type    Reason     Age                  From                     Message
  ----    ------     ----                 ----                     -------
  Normal  Sync       87s                  loadbalancer-controller  UrlMap "k8s2-um-wyu1g3bu-default-my-ingress-etd1ul6o" created
  Normal  Sync       84s                  loadbalancer-controller  TargetProxy "k8s2-tp-wyu1g3bu-default-my-ingress-etd1ul6o" created
  Normal  Sync       69s                  loadbalancer-controller  ForwardingRule "k8s2-fr-wyu1g3bu-default-my-ingress-etd1ul6o" created
  Normal  IPChanged  68s                  loadbalancer-controller  IP is now 34.98.64.104
  Normal  Sync       63s (x4 over 3m53s)  loadbalancer-controller  Scheduled for sync
% curl 34.98.64.104
curl: (52) Empty reply from server
```
Ingressはいろいろなエラーが発生する割にGoogleCloud側にトラブルシュート用の資料がなく、毎回原因の究明に苦労するので、今回のケースについて記録しておく。

# 原因
ロードバランサのデプロイが終わってなかった。しばらく待ってからリクエストを投げると今度は違うレスポンスが帰ってきた。
見かけ上IPがアサインされ、Eventsにエラーがなくsyncになっていても、実際はリクエストをまだ受け付けられない可能性がある。
GKE ingressで502が出たとき

# 何が起きたか
GKEのingressを設定してアクセスしたところ以下のエラーが出た。
```html
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>502 Server Error</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Server Error</h1>
<h2>The server encountered a temporary error and could not complete your request.<p>Please try again in 30 seconds.</h2>
<h2></h2>
</body></html>
```
ingressはいろいろなエラーが発生する割にトラブルシュートの資料がGoogleCloudになく、毎回原因の究明に苦労するので、今回のケースについて原因を残しておく

# 原因
serviceのバックエンドになるpodのlabelが間違っており、serviceがリクエストを受け付けることができてなかった。
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: default-client
  name: default-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: default-client
  template:
    metadata:
      labels:
        app: default-client # serviceのselectorと一致してない
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
```

別のpodからserviceに、直接リクエストした際にリクエストが拒否されたので判明した。
修正後は以下のとおり。
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: nginx
            port:
              number: 80
```
Databricks予算ポリシーによるサーバレスコストの部門、ユーザーへの按分

[Attribute serverless costs to departments and users with budget policies \| Databricks Blog](https://www.databricks.com/blog/attribute-serverless-costs-departments-and-users-budget-policies)の翻訳です。

:::note warn
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

# AWSとAzureでサーバレスコンピュート向けの予算ポリシーがパブリックプレビューに

Databricksサーバレスの予算ポリシーのパブリックプレビューを発表できることを嬉しく思っています。管理者は、ユーザーがタグを手動でつけることに依存することなしに、サーバレスリソースに対して自動的に適切なタグが付けられることを保証するために、予算ポリシーを活用することができ、カスタマイズされたコストレポートや配賦を可能にします。

[7月にサーバレスコンピュートの正式提供](https://www.databricks.com/jp/blog/announcing-general-availability-serverless-compute-notebooks-workflows-and-delta-live-tables)を開始して以来、お客様は高速な起動時間、円滑なオペレーション、比類なき信頼性のメリットを活用するために、ノートブック、ジョブ、Delta Live Tables(DLT)のサーバレスコンピュートを活用しています。

しかし、企業にとってはコストを特定のプロジェクト、コストセンター、部門に按分することが重要です。詳細なコスト按分によって透明性を確保し、説明責任の重要度を高め、究極的にはDatabricks利用の最適化の助けとなります。

# コスト按分のための予算ポリシーでサーバレスワークロードにタグ付けを

効果的な費用管理は、サーバレスコンピュートにおけるコスト効率性を最適化するためには重要となります。タグを用いることで、管理者はコストセンター、プロジェクト、その他の適切なカテゴリーに基づいて請求レコードをグルーピングすることができます。この戦略によって、それぞれのタグに関連づけられたコストに対する包括的な可視性を確実なものとし、部門間、プロジェクト間における予算管理をシンプルにします。

# ベストプラクティスとしてのタグの強制

サーバレス予算ポリシーを導入することで、作成される全てのサーバレスリソースに確実にタグを適用できるようになります。一つ以上のタグを含むこれらのポリシーは、特定のユーザー、グループ、サービスプリンシパルに適用することができます。

![](https://www.databricks.com/sites/default/files/inline-images/budget_policies_screenshot.png?v=1729035885)

(サーバレスコンピュートを使うように設定されたワークフロータスクやDLTパイプラインのような)サーバレスリソースを作成する際、ユーザーは割り当てられている予算ポリシーを選択することができます。多くの場合、ユーザーはデフォルトで選択される単一の予算ポリシーが割り当てられることになります。すると、この予算ポリシーのタグがサーバレスコンピュートに自動で割り当てられるようになります。

![](https://www.databricks.com/sites/default/files/inline-images/job-policy.png?v=1729182186)

お使いのDatabricksアカウントでサーバレスコンピュートが有効化されると、お使いのワークスペースのすべてのユーザーはコンピュートの選択肢としてそれらを利用できるようになります。このため、予算ポリシーを確立し、あなたのワークスペースのすべてのユーザーに対して、少なくとも一つの予算ポリシーを割り当てることがベストプラクティスとなります。これによって、すべてのサーバレスリソースが適切に考慮され、タグに関連づけられることを確実にします。

# 使い始める

あなたのアカウントでサーバレスコンピュートを有効化していないのであれば、[AWS](https://docs.databricks.com/ja/admin/workspace-settings/serverless.html)、[Azure](https://learn.microsoft.com/ja-jp/azure/databricks/admin/workspace-settings/serverless)の手順に従って有効化することができます。

*入門ディスカウントのメリットを享受しましょう: 2025/1/31まで利用できる[ジョブ](https://www.databricks.com/jp/product/pricing/jobs)と[パイプライン](https://www.databricks.com/jp/product/pricing/delta-live)のサーバレスでの50%オフ、[ノートブック](https://www.databricks.com/jp/product/pricing/datascience-ml)の30%オフを活用しましょう。この限定オファーは、コストを削減してサーバレスコンピュートを探索する完璧な機会です。*

ワークスペースでサーバレスコンピュートの予算ポリシーを設定するには、ワークスペース管理者である必要があります。我々の[AWS](https://docs.databricks.com/ja/admin/usage/budget-policies.html)と[Azure](https://learn.microsoft.com/ja-jp/azure/databricks/admin/usage/budget-policies)のドキュメントでは、予算ポリシーの設定方法の詳細を説明しています。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
JetsonにPython 3.10をインストールする手順

# 概要
いい感じのJetson NX XavierへのPython 3.10のインストール手順が
どこにもなかったので、まとめました。
ただ、私の利用しているJetsonでPython3.10をインストールしても、
`torch.cuda.is_available()`の結果は`False`だったので
結局Python3.10は使わなかったんですけどね。

# Jetsonの環境
以下に今回利用したJetsonの環境を記述します。
- NVIDIA Jetson Xavier NX Diveloper Kit - Jetpack 5.1.2[L4T 35.4.1]

| Item         | Version            |
|     :-:      |        :-:         |
| Machine      | aarch64            |
| System       | Linux              |
| Distribution | Ubuntu 20.04 focal |
| RAM          | 6.7GB              |
| Release      | 5.10.120-tegra     |
| Python       | 3.8.10             |
| CUDA         | 11.4.315           |
| cuDNN        | 8.6.0.166          |
| TensorRT     | 8.5.2.2            |
| VPI          | 2.3.9              |
| Vulkan       | 1.3.204            |
| OpenCV       | 4.5.4 with CUDA    |

# 手順
1. ソースコード配布先について
Pythonの公式サイトの[Downloadページ](https://www.python.org/downloads/source/ "Python Source Releases")に行くとソースコードへのリンクがあるので、
リンク先のアドレスを書き留めます。
今回は、Python 3.10.14の箇所にある「[XZ compressed source tarball](https://www.python.org/downloads/source/#:~:text=Gzipped%20source%20tarball-,Download%20XZ%20compressed%20source%20tarball,-Python%203.9.19%20%2D%20March "Python Source Releases")」を使います。

1. ソースコードのダウンロード
wgetを使って、上記で取得したリンク先からソースコードをダウンロードします。
`wget https://www.python.org/ftp/3.10.14/Python-3.10.14.tar.xz`

1. 解凍
取得したソースコードを解凍します。
アーカイブの拡張子が「.tar.xz」なので、「J」というオプションを使います。
`tar xJf Python-3.10.14.tar.xz`
1. ビルド
次のようにしてビルドします。
    ```
    cd Python-3.10.14
    ./configure
    make
    sudo make install
    ```
1. バージョンの確認
Pythonを起動するコマンドは「`python`」です。
コマンドに「`--version`」または「`-V`」オプションをつけて実行すると、
バージョンを確認できます。
    ```
    python -V
    >> Python 3.10.14
    ```
    上記のコマンドでバージョンが変わっていなかったら以下のコマンドを打ち込んで
    新しく追加したpythonを選択してください。
    ```
    sudo update-alternatives --config python
    ```
【shell】ややこしシャルスクリプト書き方まじリスペクト

## はじめに
実務でシェルをかく機会があり、そこで変数を代入したり変数を指定して取得したりするコードをかいています。

ややこしいのを一旦整理してみます。


## シェルに値を宣言し代入
変数に代入するときは=を使います。等号の前後にスペースを入れてはいけません。

```.sh
STAGE=st
```

```.sh
Hey="Hello, World!"
```

## 変数の参照パターン1
変数名の前に$をつけます。
簡潔でよみやすく、一般的な用途で使いたおせそうですね。

```.sh
echo $STAGE
```


<b>実行結果</b>
```
st
```

## 変数の参照パターン2
変数を${}で囲うパターン
変数名の境界を明確にしてくれます。変数後に文字列が続くときに有効です！

```.sh
TEST_A=apple
TEST_B=${TEST_A}pie🍎
echo $TEST_B
```

<b>実行結果</b>
```
applepie🍎
```

## 変数の参照パターン3
文字列を""で囲うパターン
空白の値を文字列として扱います。空白を含む値や特殊文字を保持します。

```.sh
message="Hello World"
echo $message
```

<b>実行結果</b>
```
Hello World
```

## コマンドの実行結果を参照し代入する

### パターン1
``でコマンドを囲うパターン

```.sh
TODAY=`date '+%Y%m%d'`
echo $TODAY
```

<b>実行結果</b>
```
20241021
```

### パターン2
$()でコマンドを囲うパターン

```.sh
TODAY=$(date '+%Y%m%d')
echo $TODAY
```

<b>実行結果</b>
```
20241021
```

## 変数を参照するコマンドの実行結果を代入し出力

### パターン1
``でコマンドを囲うパターン

```.sh
MONTH_DAY=$(date '+%Y%m%d')  
MONTH_DAY_OUTPUT=`echo "$MONTH_DAY" | awk '{print substr($0, 5)}'`   

echo $MONTH_DAY_OUTPUT
```

<b>実行結果</b>
```
1021
```


### パターン2
$()で囲うパターン

```.sh
MONTH_DAY=$(date '+%Y%m%d')
MONTH_DAY_OUTPUT=$(echo ${MONTH_DAY} | awk '{print substr($0, 5)}')

echo $MONTH_DAY_OUTPUT
```

<b>実行結果</b>
```
1021
```

## おわりに
変数を参照するさいに、`$()`なのか`${}`なのか、よくわからなくなりましたがここでまとめたので頭すっきりです。

ガンガンつかっていきましょう。


## 参考
https://job-info.hateblo.jp/entry/2024/08/16/215108

https://zenn.dev/sameno/articles/3f78af8e2cde3a
性能評価

## はじめに
Jmeterを利用した、Webシステムの性能評価についてまとめる


## 前提として
JmeterはJavaで動作するため、Javaのセットアップが事前に必要。

## 導入
Jmeter公式サイトより、バイナリファイルをダウンロードし、
解凍後、binフォルダにあるjmeter.batを実行することで、GUIが表示される。
https://jmeter.apache.org/download_jmeter.cgi


## 性能評価のための設定

### 1. Planの配下に、Thread Groupを作成する

Thread Groupは評価を行いたいリクエストの回数などを定義できる。
※GUIの左ペインのツリー上のPlanを右クリックし、追加[Add]からThreadsを選択し追加する。

|主な設定項目|説明|
|---|---|
|スレッド数(users) [Number of Threads]|リクエストの回数|
|Ramp-up期間(seconds) [Ramp-up period]|連続してリクエストを投げる期間|
|ループ間隔 [Loop Count]|スレッドを何回繰り返すか|

例：
スレッド数：5、Ramp-up期間：5、ループ間隔：2
※5回のリクエストを5秒以内で実行しそれを2ループする設定となる。
※5秒で5回なので、1秒間隔でリクエストされるイメージ。
※2ループなので、結果的には10秒の間に1秒間隔でトータル10回リクエストが実行されることとなる。

### 2. Thread Group 配下にリクエストを定義する

リクエストの種類を選択し、具体的なリクエストの定義を行う。
※GUIの左ペインのツリー上のThreadを右クリックし、追加[Add]、サンプラー[Samplar]から該当するリクエストを選択し追加する。

※Webシステムの場合はHTTPリクエストを選択する。


### 3. Listner を作成する

実行結果を閲覧するために リスナーを作成する
※GUIの左ペインのツリー上のThread配下のリクエストを右クリックし、追加[Add]、リスナー[Listner]から「結果を表で表示」[View Results in Table]、[Summary Report]、[View Results Tree]を選択し追加する。


Sample Time(ms)：リクエストの送信からレスポンスを受けるまでにかかった時間
Latency：リクエストを送ってからレスポンスが届いた時間
なぜ Vue 2 では props の型がオブジェクトまたは配列の場合、デフォルト値は必ず関数である必要があるのか？

## 1. なぜ Vue 2 では props の型がオブジェクトまたは配列の場合、デフォルト値は必ず関数である必要があるのか？

Vue 2 では、props の型がオブジェクト（Object）または配列（Array）の場合、デフォルト値として関数を使用することが推奨されている理由は以下の通りです：

- **オブジェクトの特性**：javascriptではオブジェクトはデフォルトでミュータブルです。直接オブジェクトをデフォルト値として設定すると、そのデフォルト値はメモリ上で共有され、デフォルト値を使用するすべてのコンポーネントインスタンスが同じオブジェクトの参照を共有することになります。

  **JavaScript において、プリミティブ以外をオブジェクトと呼ばれます**

  **プリミティブ (primitive、プリミティブ値、プリミティブデータ型) はオブジェクトでなく、メソッドを持たないデータのことです。**

  ````
  以下の内容は、読みやすさと理解を容易にするために、オブジェクトと配列のまま記述しています。しかし、上記の説明に基づき、JavaScriptにおいて配列はオブジェクトに属することをご了承ください
  ````

  

- **潜在的なデータ汚染**：これにより、あるコンポーネントインスタンスがこのオブジェクトや配列を変更した場合、その変更がデフォルト値を使用しているすべての他のコンポーネントインスタンスに影響を及ぼすことになります。これは通常、私たちが期待する動作ではありません。

- **新しいインスタンスを返す関数の使用**：この問題を避けるために、Vue はこのような参照型の props に対して、デフォルト値を新しいオブジェクトまたは配列インスタンスを返す関数で指定することを要求します。こうすることで、新しいコンポーネントインスタンスを作成するたびにこの関数が呼ばれ、それぞれのインスタンスに独立した、他のインスタンスと共有されないデフォルト値が提供されます。

### 例：

```javascript
props: {
  items: {
    type: Array,
    default: () => [] // 新しい空の配列をデフォルト値として返す
  },
  config: {
    type: Object,
    default: () => ({}) // 新しい空のオブジェクトをデフォルト値として返す
  }
}
```

このようにすることで、各コンポーネントインスタンスの `items` と `config` prop は、それぞれ独立したデフォルト値のコピーを持つことになり、データの隔離性が保証され、潜在的なデータの交差汚染問題を防ぐことができます。

---

## 2. Vue 2 における props の値の型とデフォルト値設定

### 2.1. props の値の型

Vue 2 では、props の値にはさまざまな型があり、以下のようなものが含まれますが、これに限定されません：

- **String（文字列）**
- **Number（数値）**
- **Boolean（真偽値）**
- **Array（配列）**
- **Object（オブジェクト）**
- **Function（関数）**
- **Date（日時）**
- **Symbol（シンボル）** - より新しいバージョンの Vue および JavaScript 環境で使用可能
- **null および undefined** - props の型やデフォルト値としても使用できます

これらの props のデフォルト値を設定する際、原始的な型（文字列、数値、真偽値など）には直接値を代入できますが、オブジェクトの場合は、新しいインスタンスを返すファクトリ関数を通じてデフォルト値を設定する必要があります。これにより、各コンポーネントインスタンスが共有されることなく、常に新しいインスタンスを取得できるようになります。

### 2.2. props デフォルト値設定の例

以下は、異なる型の props とそのデフォルト値設定の例です：

```javascript
Vue.component('my-component', {
  props: {
    // 文字列型、デフォルトは空文字列
    text: {
      type: String,
      default: ''
    },

    // 数値型、デフォルトは0
    count: {
      type: Number,
      default: 0
    },

    // 真偽値型、デフォルトはfalse
    isActive: {
      type: Boolean,
      default: false
    },

    // 配列型、デフォルトは空配列
    items: {
      type: Array,
      default: () => []
    },

    // オブジェクト型、デフォルトは空オブジェクト
    config: {
      type: Object,
      default: () => ({})
    },

    // 関数型、デフォルトは空関数
    callback: {
      type: Function,
      default: () => {}
    },

    // 日時型、デフォルトは現在の日時
    date: {
      type: Date,
      default: () => new Date()
    }
  },
  // ...その他のコンポーネントロジック
});
```

上記の例では、配列、オブジェクト、および日時などの複雑な型に対しては(**実際にはすべてオブジェクトですが、理解しやすくするためにこのように書いています**)、矢印関数を使用して新しいインスタンスを返すことで、異なるコンポーネントインスタンス間で同じデフォルト値を共有する問題を避けています。一方、文字列、数値、真偽値などの基本型に対しては、直接デフォルト値を設定できます。関数型に関しては、参照型ではないものの、一貫性を保つために矢印関数を使用してデフォルト値を定義することが推奨されます。
webpack

<h1>▼webpackを使用する</h1>
1. 

```
npm init -y
```
2.WebpackとWebpack CLIをインストール
```
npm install --save-dev webpack webpack-cli
```

3.ディレクトリ構造
```
my-project/
  ├── src/
  │   └── index.js  // エントリーポイント（アプリの起点）
  └── dist/
      └── bundle.js  // 出力ファイル
```

4.webpack.config.js設定ファイル
```
const path = require('path');
module.exports = {
  entry: './src/index.js', // エントリーポイント
  output: {
    filename: 'bundle.js', // 出力ファイル名
    path: path.resolve(__dirname, 'dist'), // 出力ディレクトリ
  },
  mode: 'development', // 開発モード
};

```
5.package.jsonでwebpack実行設定
```
{
  "name": "my-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "devDependencies": {
    "webpack": "^5.0.0",
    "webpack-cli": "^4.0.0"
  }
}
```

6.実行
```
npm run build
```


<h1>▼自動で実行設定</h1>
1. 開発中にファイルを自動でリビルドしてくれるWebpack Dev Serverをインストール

```
npm install --save-dev webpack-dev-server
```
2.package.jsonに追加設定
```
"scripts": {
  "start": "webpack serve"
}
```

3.実行
```
npm start
```

<h1>▼gulpのwathとwebpack Dev serverの同時実行</h1>
1.concurrentlyパッケージツールをインストール

```
npm install concurrently --save-dev
```


2.package.jsonに追加設定
```
{
  "scripts": {
    "start": "concurrently \"npm run gulp\" \"npm run webpack\"",
    "gulp": "gulp",
    "webpack": "webpack serve"
  }
}
```

3.実行
```
npm start
```


<h1>wordpressにcssを読み込む</h1>
▼gulpで生成されたcssを読み込む

1.functions.phpに設定

```
  function my_theme_enqueue_styles() {
    wp_enqueue_style('main-styles', get_template_directory_uri() . '/public/css/style.css', array(), time());
  }
  add_action('wp_enqueue_scripts', 'my_theme_enqueue_styles');
```

:::note info
headのlinkタグに読み込まず、functions.phpに記載する
:::

<h1>wordpressにjsを読み込む</h1>

```
function my_custom_scripts() {
  // JavaScriptファイルを読み込む
  wp_enqueue_script(
    'my-script',
    get_template_directory_uri() . '/dist/bundle.js',
    array(),
    time(), // キャッシュを回避するため、バージョン番号に現在のタイムスタンプを使用
    true
);
}
add_action('wp_enqueue_scripts', 'my_custom_scripts');
```

footerに読み込み
```
<?php wp_footer(); ?>
</body>
</html>
```
OpenVPN経由でWindows 10の共有フォルダにつながらない

## 概要
- VPS上のRocky Linuxで動かしているOpenVPNを経由してWindows10の共有フォルダにつながらない。
- つながっても接続が安定しない。
## 原因と対策
- Windows10にてWindows Updateを直前に行っていたためにWindowsのファイヤーウォールが有効になっていて接続できなかった。Windows側のファイヤーウォールの設定が必要だった。
- Windows側のクライアントをOpenVPN ConnectからOpenVPN-2.6.12に変更したら接続が安定した。
AstroでMarkdown内の外部リンクを新しいタブで開く方法

Astroを使ってMarkdownファイル内の外部リンクを新しいタブで開く方法について解説します。

### 手順

1. **必要なパッケージのインストール**

   まず、`rehype-external-links`をインストールします。ターミナルで以下のコマンドを実行してください。

   ```bash
   npm install rehype-external-links
   ```

2. **Astroの設定ファイルを更新**

   次に、`astro.config.mjs`（または`astro.config.js`）ファイルを開き、Markdown設定に`rehype-external-links`を追加します。以下のコードを参考にしてください。

   ```javascript
   // @ts-check
   import { defineConfig } from 'astro/config';
   import rehypeExternalLinks from 'rehype-external-links';

   // https://astro.build/config
   export default defineConfig({
     markdown: {
       rehypePlugins: [
         [
           rehypeExternalLinks,
           {
             target: '_blank', // 外部リンクを新しいタブで開く
             rel: ['noopener', 'noreferrer'], // セキュリティ対策
             content: { type: 'text', value: ' 🔗' }, // 外部リンクアイコン（オプション）
           },
         ],
       ],
     },
   });
   ```

3. **Markdownファイルの作成**

   これでMarkdown内の外部リンクは新しいタブで開かれるようになります。以下のようにMarkdownファイル内でリンクを追加します。

   ```markdown
   [外部サイト](https://example.com)
   ```

これで、Astroを使ってMarkdown内の外部リンクを新しいタブで開く設定ができました。ぜひ活用してみてください！
Laravelの初期設定について

# はじめに
学習のためLaravelでアプリを作成した際の状況をメモした備忘録です

誤りや新しい情報を得た場合は都度更新します

## 前提条件
Laravelでアプリを作成する場合は以下の条件を満たしている必要があります

- PHPのインストール
- Composer(コンポーザー）のインストール

## プロジェクトを新規作成する

以下のコマンドで最新バージョンのLaravelプロジェクトを作成します
```
composer create-project --prefer-dist laravel/laravel プロジェクト名
```
### プロジェクト名について
特に厳密なルールはないものの、一般的にキャメルケース または スネークケースで名称を付けられています

#### 例
- CustomerManagementApp
- customer_management_app
- InventoryTracker
- inventory_tracker
- TaskManager
- task_manager



### バージョンを指定する場合

Laravel 8.xを指定してプロジェクトを作成したい場合
```
composer create-project --prefer-dist laravel/laravel crm "8.*"
```
#### 特定のバージョンを指定する（補足）
特定のメジャーバージョン: 8.*（8.x系を指定）
特定のマイナーバージョン: 8.0.*（8.0系を指定）
特定のパッチバージョン: 8.0.1（特定のバージョンを指定）

## データベースと接続する

作成したプロジェクトのルートに存在する.envファイルは、Laravelアプリケーションの環境設定を管理するための重要なファイルです。ここにデータベースの接続情報を保存することで、Laravelとデータベースを接続する準備が整います

```
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=crm
DB_USERNAME=root
DB_PASSWORD=root
```
### 接続情報の補足
- **DB_CONNECTION** : 使用するデータベースドライバを指定します(例:MySQLを使用する場合はmysql)

- **DB_HOST** : データベースサーバーのホスト名を指定します（ローカル環境の場合は127.0.0.1やlocalhostが一般的）

- **DB_PORT** : データベースがリッスンしているポート番号を指定します（MySQLのデフォルトは3306)

- **DB_DATABASE** : 接続するデータベースの名前を指定します（例: crm）

- **DB_USERNAME** : データベースに接続するためのユーザー名を指定します（例: laravel）


## 接続確認
マイグレーションコマンドを実行した際にエラーが発生しなければ接続が成功していることを確認できます
```
php artisan migrate
```
デジタルツインと3Dモデルの違い：仮想世界の異なる側面

今日のデジタル化された世界では、「デジタルツイン」と「3Dモデル」は頻繁に聞かれる技術用語です。一見似ているように思えますが、実際の用途や機能には大きな違いがあります。これらの違いを理解することで、異なる場面でそれぞれの技術の利点を最大限に活かすことができます。

**3Dモデル：物体の静的な仮想表現**

3Dモデルは、コンピュータソフトウェアや3Dスキャナーを使用して作成された物体の三次元表現です。主に現実の物体の形状を模倣し、設計や表示、製造の基盤ツールとして使用されます。建築設計や映画アニメーション、製品のプロトタイプ製造など、幅広い分野で欠かせない存在です。本質的には静的なジオメトリの形状であり、物理的な振る舞いや環境データ、状態の変化を含むことはありません。例えば、MIRACO 3Dスキャナーを使用して物体をスキャンすると、正確な3Dモデルが生成され、ユーザーはソフトウェアでの設計や編集が可能になります。
![cd8e31200114271357b68ab48dbe2d88.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/e9e15bfc-e538-6a72-7ec9-d24d147a7e15.png)

https://www.revopoint3d.jp/products/all-in-one-3d-scanner-miracoplus


**デジタルツイン：物理とデジタルの世界をつなぐ架け橋**

一方、デジタルツインは単なる仮想形態のコピーではなく、現実世界の物体やシステムと密接に連携しています。デジタルツインは、センサーやIoTなどの技術を介して物理世界のデータをリアルタイムで収集し、仮想空間で同期させます。これにより、物理システムの運用をシミュレート、予測、最適化できるため、産業機器の監視やスマートシティ管理、製品ライフサイクル管理などの複雑なシステムに広く活用されています。デジタルツインは、静的な形状だけでなく、動的なデータや振る舞いのフィードバックも可能であるため、より知的な管理が求められる場面で重要な役割を果たします。
![d28524d49382fa0d7f54ca0c16aa8129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/999dc51d-a83d-3479-1d95-8b6b30481255.png)

**まとめ：静的と動的の根本的な違い**

簡単に言うと、3Dモデルは物体の静的な形状を表現し、設計や表示に利用されます。それに対し、デジタルツインは物理世界とリアルタイムで相互作用する仮想コピーであり、動的なデータと行動シミュレーションを含みます。どちらも三次元空間を基盤としていますが、デジタルツインはリアルタイムの監視やシステムの最適化に重きを置いており、複雑なシステムの管理に適しています。
投稿 112 Ruby② 2024/10/20

本日の勉強時間　3H


まつもと ゆきひろ

まつもとゆきひろ（2007年撮影）
生誕	1965年4月14日（59歳）[1]
大阪府[1]
国籍	日本の旗 日本
別名	Matz


オブジェクト指向プログラミング言語（スクリプト言語）「Ruby」の開発者として知られる。

氏名は一般に平仮名で表記されることが多い。通称はMatz（マッツ）で、英語圏などで広く定着している。
Dockerの基礎

## Dockerとは
　Dockerはコンテナを使い仮想空間を作り出しアプリケーションを軽量かつ構築を素早くし、開発をスムーズにすることができるツール

## Dockerインストールについて
[Docker Desktop インストール手順](https://qiita.com/R_R/items/a09fab09ce9fa9e905c5)
を参考にインストールを実行

## Dockerの基本操作について
　・コンテナについて
    コンテナ：パソコンやサーバ上で隔離され、干渉されない環境。コンテナには小さなパソコンが入っているような状態。ホストOS(使っているパソコン)はコンテナがあると干渉されなくなる。
  コンテナは１つのホストOSで複数のコンテナを配置することができ、さらに他のコンテナにも干渉することはない。


　・イメージについて
     イメージ：イメージとはコンテナの型となるものであり、必要なソフトウェア・環境変数・設定などが情報に入っている。

### Dockerに関する基礎コマンド
【イメージのダウンロード】
```
$ docker image pull イメージ名
```
-----
【ローカルマシンに存在するイメージ一覧を表示するコマンド】
```
$ docker iamge ls
```
---

【ローカルマシンに存在するイメージを削除するコマンド】
```
$ docker image rm イメージ名
```
---
【イメージからコンテナを作成し起動するコマンド】
```
$ docker container run イメージ名
```
---

【ローカルマシンに存在するコンテナ一覧を表示するコマンド】
```
$ docker container ls
```
---

【起動中のコンテナを止めるコマンド】
```
$ docker container stop コンテナ名
```
---

【コンテナを再起動する(upする)コマンド】
```
$ docker container restart コンテナ名
```
---

【コンテナを破棄するコマンド】
```
$ docker container rm コンテナ名
```
問題構造ツリーのアレンジ

# 前提
TOCの思考プロセスツリーの1つである現状構造ツリー、未来構造ツリーについては、
ググれば詳細が色々出てくるので、そちらを参照ください。

ここでは各ステークホルダーの関心が把握しやすいように、
その各ステークホルダーの見ている抽象度合い(ミクロなスコープなのか、マクロなのか)
を意識した、問題構造ツリーにアレンジして使ってみたUDEマップの内容を記載する。

# 背景
前職で未来問題構造ツリーを作成していた際に、
各DEの要素が誰にとっての嬉しい結果なのか？などをその都度ステークホルダーマップと
行き来しながら整合性を測るというちょうぜつ面倒くさい体験があった。

その図が固定的であるならともかく、ステークホルダーにとってのUDE(望ましくない状態)
やDE(望ましい状態)は、変化するものであるので、
問題構造ツリーを見たら、そのDEなどがどのステークホルダーにとっての関心なのか？
などを瞬時に見分けられると嬉しいな　といういきさつがあった。

そこでUAF(下図)のように抽象度を意識した構造ツリーであった方が、
見やすいし、仮にあるステークホルダーにとってのDEが変化した際にも、
速やかに図を更新しやすいだろうと思って、今回の実験を思いついた。

![UAFGrid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781175/b11eb628-49a1-4cd5-0b8b-3f5d9b3ae134.png)

# 何をやるのか
やることはシンプル。
問題構造ツリーに対して、各UDEやDEの抽象度をそろえて図を作成するだけの話。

![27-figure01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781175/dc794255-a0eb-c5e6-1229-c62a72d6b1fb.gif)

要は、上図のように各抽象度ごとに関心を区切って考えるということ。
上の段の方に行けば行くほどUAFでいうStrategicビューなどの関心、
下の段に行くほどResourceなどの具体的なビューの関心になるように配置することを心掛ける。


# どうやってやるのか
UAFの状態列とはまた別で、UDEとDEが考えられる列を追加して考えてみる。

そして何よりも、まずはスコープの範囲を最初に決める。
企業全体で考えいのか？　それともまずはお試しとして初期投資を抑えるために、
１つの事業の範囲内でのみ考えるのか？といったことを定義する。

Resourceビュー(具体)から全体像をマクロに見る事業戦略や経営戦略を考える。
１つの事業のスコープでのみ考えるのならば、Strategicは事業戦略ビューになり、
事業戦略を考えるステークホルダーの関心が最上位になるように配置して考える。

とりあえずUDEをブワーって列挙しってやってるとあっという間に発散して、
ノイズが多くて何が本質的な要素なのか？がわかりにくくなるし、
収束させづらいので、兎に角　各抽象度ごとステークホルダーの関心であるUDEを抽出する。

その要素の中で上位下位概念のUDEと因果関係で明らかに結びつくようなものを結んでいく。


# より応用的な内容
匠の価値分析モデルにある、価値記述と組み合わせることでより威力を発揮すると思っている。

どのように使うかというと、
「UDEからDEに変化することで、価値である〇〇が実現できるからうれしい」
というように、現状問題構造ツリーと未来問題構造ツリーとを比較して、
現状から未来ツリーの方に移行することによって、各ステークホルダーの価値は叶うか？
そのステークホルダーにとっての価値はいったい何なのか？
ということまで浮き彫りにしやすい。

いきなり価値を抽出するということは、圧倒的に困難な場合が多いので、
私自身はこの方法をお勧めしています。

![20180614012203.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781175/5196e1d8-c049-6261-7a7d-a24445d0dff0.jpeg)

## 価値を特定後にDEを更新
「あなたにとっての価値を言ってください」と言っても、
言語化できないステークホルダーは非常に多いので、
まずは「不満に思ってることを教えてください」とUDEを抽出し、
そこからDEを考えて、UDE→DEへ変えたい理由として【どんな価値】を叶えたいか？
の精度がぐっと向上する。

しかもそれはより精度の高いユーザーストーリーマップを作成できることにもつながる。

価値を特定できたとしたら、「だとしたら本当のDEってそれでなく、これだよね」
といったような修正もしやすくなる。
秀和システム「Python x API で動かして学ぶ AI活用プログラミング」０章

秀和システム「Python x API で動かして学ぶ AI活用プログラミング」
０章をやってみた。
ここでは記事の内容ではなく、自環境での動作結果だけを記録のために記載しています。

## 環境
OS：Windows 11 Home 64 ビット オペレーティング システム
CPU：11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz   3.00 GHz
RAM：32.0 GB

## ソース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/dc50675c-070a-dbbb-7f0a-405f8dfec035.png)
（中略）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/d2ff5305-83d5-8f9d-d155-16a9bf737e4f.png)

```0_HelloStreamlit_app.py
import streamlit as st

st.title('計算アプリ')

# Input
a = st.number_input('数字1')
b = st.number_input('数字2')
method = st.sidebar.selectbox("計算方法", ['足し算', '掛け算'])

# process
if method == '足し算':
  c = a + b
elif method == '掛け算':
  c = a * b

# output
st.title('計算結果')
st.text(c)
```

## 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/ba58924b-ffdf-767b-07f8-09b61d883978.png)
ReactとNext.jsでフロント、Pythonでバックエンドを開発し、Vercelへデプロイした話。ついでにSquidとngrokでプロキシサーバも作った！

# 作ったアプリの内容
- 今回作ったのは、YouTubeをキーワード検索して、視聴回数が多い順に結果を表示し、各動画の字幕をダウンロードして要約してくれるアプリです。(検索結果を10件以下にすると、一気にまとめて要約する機能もあります。)
[Github](https://github.com/sinzy0925/vercel-youtube-search "https://github.com/sinzy0925/vercel-youtube-search")
アプリのURL [vercel](https://frontend-rho-steel-59.vercel.app/ "vercel") （vercelは、URLの更新漏れが有ると思います。）

###

- フロントエンドにはReactとNext.jsを使い、バックエンドはPythonで組みました。フロントはUIに関して知識がほとんどない中で作ったので、具体的な部分は割愛しますが、検索キーワードの入力と結果の表示が主な機能です。
###

- バックエンドは、主に以下の機能があります：
A: YouTube検索(youtubesearchpythonライブラリ)
B: YouTubeの字幕取得(youtube_transcript_api)
C: 字幕の要約(LLM : gemini-1.5-flash)
実際の開発では、フロントとバックエンドの通信がうまくいかないことや、YouTubeから字幕取得の際にアクセスを拒否される問題が発生。そこでプロキシサーバが必要になり、Squidとngrokを使って2日間かけて解決しました。
###

- アプリ開発で問題になったこと：
・フロントとバックの通信問題。
・YouTubeからのアクセス拒否による字幕取得の失敗。
・プロキシサーバの構築に苦労（2日もかかる）。
　分からないことだらけでも、AIやGoogle検索を駆使して、なんとか乗り切れたのが嬉しかったです。
###

- cursorの良かった点
最近はAIツールも多く登場していますが、私が使っているのは「cursor」です。個人的に一番しっくりくるのは、自由度が高く、ソースコードの修正ポイントが見やすい点です。AIとのやり取りもスムーズで、とても直感的に操作できました。
素人の私が言うのもなんですが、プロのエンジニアなら、開発効率が劇的に向上するツールだと感じています。cursorがある環境なら、開発スピードが上がり、やるべきことに集中できるのではないかと思います。
開発環境がインターネットに繋がってないとか悲劇ですね。
###

- cursorの辛かった点
cursorを使っていて辛かったのは、AIが答えを出せない場合です。同じ質問を繰り返しても、解決に至らないことがあります。これは自分の質問の仕方が悪かったのかもしれませんが、その「ハマり感」は確かにありました。行き詰まったときには、少しパソコンから離れて気分転換するのが大事だと感じました。
###
- Vercelへデプロイした際にハマったこと
フロントエンドとバックエンドをVercelにそれぞれデプロイしたところ、通信がうまくいきませんでした。cursorに確認したところ、別々のドメイン扱いになってしまうので、CORS（クロスオリジンリソース共有）設定が必要だと言われました。しかし、調べてもなかなか解決できず、結局1日がかりで試行錯誤。
　
　最終的には、Vercelのvercel.jsonを編集することで、2つのアプリを1つのドメインとして認識させる方法にたどり着きました。ここでもcursorに助けられましたが、丸1日かかってしまいました。
###
- Squidとngrokでプロキシサーバを作った話
通信が解決したと思ったら、次はYouTube字幕取得の際にアクセス拒否される問題が発生。これを解決するために、Squidとngrokを使って自宅PCをプロキシサーバにしました。しかし、このプロセスが難航し、さらに1日かかりました。

　翌朝、冷静にそれぞれの機能を確認しつつ再度チャレンジしたところ、何とか動かすことができました。ここまで苦労した分、少しは自分の成長を感じました（とはいえ、多分そんなことはないです）。
###

- 終わりに
セキュリティ面にはまだ課題が残っているし、UIも改善点が山積みですが、アプリが動いた瞬間は本当に嬉しかったです。この記事を読んでくれた人が、何かしら参考にしてくれたら幸いです。
それと、プロキシサーバは自宅サーバかつ、自宅にWIFIは無くテザリングのみで開発中なので、ほとんど稼働してません。悪しからず。フロントエンドの画面のみ確認できます。
###
- 次の記事で、ハマりポイントになった部分の詳細を記載予定です
###
- GitHubにソースコードは公開していますので、気になる方はぜひチェックしてください

以上、Vercelにデプロイした際の苦労話や、プロキシサーバを使って解決した経験について共有させていただきました！
ACDLを提唱します。その14

# 概要
ACDLとは、アプリは、クラウド、大切なデータは、ローカルです。
素晴らしいアプリ見つけたので、plunkerに上げてみた。

# 参考にしたページ

https://qiita.com/tetsutakamurata76/items/5ad5ae5776de260eeb54

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/4313dae5-c68b-bf11-f476-a8095d871437.png)

# 成果物

https://embed.plnkr.co/plunk/foWaAQEEKQZmZaD4


以上
【Ruby】初学者向け－モジュールとミックスインについて

## モジュールとミックスインについて

本記事はモジュール・ミックスインについてまとめていきます。

### モジュール
…特定のメソッドをまとめておけるもの。
　複数のクラスで使用する共通のメソッドをモジュールとして定義できる。モジュール内に書いたメソッドや定数は様々な箇所で使用できる


```ruby:example_1.rb
    module TestModule
        CONST_NUM = 100
        
        def const_num
            CONST_NUM
        end
    end

    # モジュールへのアクセス方法１
    puts TestModule::CONST_NUM
    =>100

    # モジュールへのアクセス方法２
    # include <モジュール名>を記述することで、モジュールに定義されたメソッドを関数のように呼び出すことができる
    include TestModule

    # モジュールをincludeした後であれば、モジュール名を省略して定数に直接アクセスすることができる
    puts const_num
    =>100
    puts CONST_NUM
    =>100
```

---------------------------------------------------
単純にモジュールに書いたメソッドに対して直接メソッドを呼び出すことはできない。
しかし、モジュールファンクションとして定義することで
クラスメソッドのようにモジュールのメソッドを呼び出すことができる。
```ruby:example_1.rb
module TestModule
    def module_function_sum(a, b)
        a + b
    end
    module_function :module_function
end

puts TestModule.module_function_sum(3,3)
=> 6
```
---------------------------------------
### ミックスイン
　…モジュールの機能をクラスに取り込むことができる。
 複数のクラスで使う共通のメソッドをモジュールとして定義しておき、適宜includeして使用したり、特定のメソッドをモジュールとしてまとめておいてユーティリティとして使用するなどの使い方がある。

#### ユーティリティ
…多目的や汎用性が高いもののこと。

```ruby:example_2.rb
    module TestModule
        def sum(a, b)
            a + b
        end
    end

    class Test
        # include <モジュール名>を記述することで、モジュールに定義されたメソッドを呼び出すことができる。
        include TestModule

        def call_sum(a, b)
            sum(a, b)
        end
    end

    test = Test.new

    puts test.sum(1,1)
    => 2

    puts test.call_sum(2,2)
    =>4
```
合同会社設立時の設立書類に、マイナンバーカードでPDFに電子署名する方法

動作環境 Windows 11

1. Windowsを用意する
1. JPKIソフトをインストールする(参考:https://www.jpki.go.jp/download/index.html)
1. Adobe Acrobat Pro(☆32bit版)をインストールする
1. Adobeに課金する
1. 政府のサイトを開く(https://www.touki-kyoutaku-online.moj.go.jp/download_soft.html)
1. PDF署名プラグイン(SignedPDF)をインストールする
1. Adobe Acrobatを再起動する
1. Adobe Acrobatのハンバーガーメニュー→環境設定→一般→セキュリティ(拡張)を開き、「起動時に保護モードを有効にする」のボタンをはずす
1. Adobe Acrobatのハンバーガーメニュー→環境設定→署名を開き、「デフォルトの署名方法」からSignedPDFを選ぶ(出てこなかったら、32bitじゃないか、課金できてないか、再起動してないか)
1. Adobe Acrobatのハンバーガーメニュー→プラグイン→SignedPDFを開く
1. 「公的個人認証ICカード」＞「設定」を選択
1. 署名情報入力画面【既定値設定】にて名前(本名)、署名地、理由(私はこの文書の作者です)を入力
1. Adobe Acrobatで、マイナンバーカードで電子署名を行うPDFファイルを開く
1. 左の「すべてのツール」→「証明書を使用」→「デジタル署名」を選ぶ
1. 署名を入れるスペースをドラッグで指定
1. ポップアップが出てくるので、電子証明書のパスワード(☆PINではない。6文字以上の英数混合の文字列)
1. 保存先ディレクトリと保存ファイル名を指定
1. 「この製品では、検証はできません。」と表示が出るが、そのまま「OK」
1. お疲れ様です。終了です。

参考文献(古い情報が多いので、あまり参考にしないでください。僕のこの文章が真実です。)

https://yoff.jp/20210131/

https://community.adobe.com/t5/acrobat%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A9%E3%83%A0-discussions/signedpdf%E3%81%AE%E9%9B%BB%E5%AD%90%E7%BD%B2%E5%90%8D%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%8C-%E3%81%86%E3%81%BE%E3%81%8F%E8%A8%AD%E5%AE%9A%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84/m-p/11807293?profile.language=ja

https://helpx.adobe.com/jp/acrobat/kb/cq04060649.html

何かアップデートがあったら、コメントで教えてください。
もっと簡単なやり方があるって場合も教えてください。
【Flutter】CenterウィジェットでColumnが上下真ん中にならない

# 概要
`Center`で`Column`を囲んでいるのに真ん中にならない問題についての備忘録  
調べればいくらでもでできますが個人のメモとして。。。

# 結論
`Column`に`mainAxisSize: MainAxisSize.min`プロパティを加える

# 問題
```
Center(
    child: Column(
        children: [
            Text('テキスト1'),
            Text('テキスト2')
            ],
         ),
     );
```


# 解決方法

```
Center(
    child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
            Text('テキスト1'),
            Text('テキスト2')
            ],
         ),
     );
```
SecLists備忘録

# インストール
https://github.com/danielmiessler/SecLists

# よく使うやつ
| パス | 名前 | 用途 |
|:-:|:-:|:-:|
| Passwords/Leaked-Databases  | rockyou.txt  | 辞書攻撃|
| Discovery/DNS  |  subdomains-top1million-5000.txt　 |  サブドメインファジング |
|  Discovery/Web-Content | burp-parameter-names.txt  |  パラメーターファジング |
|  Discovery/Web-Content | directory-list-2.3-small.txt  |  ページファジング |
|  Discovery/Web-Content | web-extensions.txt  |  ページファジング |
ジョブカン経費精算/ワークフローAPI（β版）を使ってみる



https://ssl.wf.jobcan.jp/api_doc#form

とりあえず、postmanから呼び出してみます。


:::note alert
{"detail":"Invalid token header. Token string is not found."}
:::

401エラーになる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/2db7f0c9-b50c-4b84-217b-99a1cbd64d48.png)


+ [PythonでアクセストークンつきHTTPリクエストを行い、ジョブカンWF APIにアクセスする](https://teratail.com/questions/247658)

:::note
ドキュメントの「Authorization: Token 管理画面より発行されたAPIトークン」を、「Token」の部分を実際のトークンに置き換えるものだと勘違いしていました。
:::

えええええ、Tokenの部分に文字列を入れてたよ。私も...


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6adda8fc-e77c-57e0-ef09-5e7b89e30b90.png)

Tokenとブランクが必要とは...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6a6dde93-95ba-5386-d7d0-ca9caf84ecfc.png)

200が返ってきた...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6d0f09f7-3a2e-879d-9ba4-444858fcadca.png)

# API Tokenの場所

個人のプロファイル --> 会社情報　--> 共通ID連携・API管理

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/205d7232-4322-929b-2a14-5b067a9182d2.png)

# Userの取得

404エラーだ。

:::note alert
The requested resource was not found on this server.
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/fcfe9fc6-82f9-1fb4-5287-11b1a353551e.png)

ブランクがある..... %20だ

```
https://ssl.wf.jobcan.jp/wf_api%20/v1/users/
```
javaでよく使う日時フォーマットパターン

```
import java.time.format.DateTimeFormatter;

public class DateTimeFormats {
    // 年月日（例: 2024年10月21日）
    public static final DateTimeFormatter YYYY_MM_DD_JP = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

    // 年月日（スラッシュ区切り、例: 2024/10/21）
    public static final DateTimeFormatter YYYY_MM_DD_SLASH = DateTimeFormatter.ofPattern("yyyy/MM/dd");

    // 年月日（ハイフン区切り、例: 2024-10-21）
    public static final DateTimeFormatter YYYY_MM_DD_HYPHEN = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    // 年月日時分秒（例: 2024年10月21日 15時30分45秒）
    public static final DateTimeFormatter YYYY_MM_DD_HH_MM_SS_JP = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH時mm分ss秒");

    // 年月日 時間（例: 2024/10/21 15:30:45）
    public static final DateTimeFormatter YYYY_MM_DD_HH_MM_SS_SLASH = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

    // 年月日 時間（ハイフン区切り、例: 2024-10-21 15:30:45）
    public static final DateTimeFormatter YYYY_MM_DD_HH_MM_SS_HYPHEN = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    // ISO標準形式（例: 2024-10-21T15:30:45）
    public static final DateTimeFormatter ISO_DATE_TIME = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

    // 年月のみ（例: 2024年10月）
    public static final DateTimeFormatter YYYY_MM_JP = DateTimeFormatter.ofPattern("yyyy年MM月");

    // 月日（例: 10月21日）
    public static final DateTimeFormatter MM_DD_JP = DateTimeFormatter.ofPattern("MM月dd日");

    // 時分秒（例: 15:30:45）
    public static final DateTimeFormatter HH_MM_SS = DateTimeFormatter.ofPattern("HH:mm:ss");
}
```
無料でAIエディタを体験する方法

## AIエディタ…使ってみたいけど……

**AIエディタ**使ってみたい！と、多くの人は思っているでしょう。
しかし、一部（例えば私）にはお金をかけたくない！と思っているケチもいるでしょう。

そこで、無料でA Iエディタを使う方法をいくつか紹介。

## ①体験版
最も一般的な手段です。ここでは私が体験したものをいくつか紹介。

### pycharm
![スクリーンショット 2024-10-21 15.52.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827586/5553d1be-9ce5-2284-c144-d6fb83d119fb.png)
↓pycharmのダウンロードはこちら
(https://www.jetbrains.com/ja-jp/pycharm/)
↓学生はこちらを使おう！
(https://www.jetbrains.com/ja-jp/community/education/#students)

ダウンロードしたpycharmを開くと、右端のバーにAI Assistantがあり、そこからダウンロードできる（体験期間は30日間）

![スクリーンショット 2024-10-21 15.56.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827586/531ed7b2-1d1b-cfc5-1e63-c9b378d76a42.png)

### Cursor
名前くらいは聞いた事があるかもしれない。
ザ・AIエディタの一つ。 １ヶ月ごとのAIの使用回数に上限のあるHobbyプラン（無料版）がある。
![スクリーンショット 2024-10-21 16.02.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827586/bf0c9d36-5c5d-f281-c640-797412f0701c.png)
(https://www.cursor.com/)
VSCodeをベースにしているので、VSCodeの拡張機能も使う事ができる。
Hobbyプランには２週間のProプラン体験と、月２０００回のAI使用などが含まれる。
使用できるAIはClaude,chatgptがメイン。OpenAIのAPIキーなども使える。

## Codeium

この記事の本命。なんと、完全無料・AI使用無制限のプランがある。
![スクリーンショット 2024-10-21 16.12.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827586/abaef11b-957d-b3b5-bbe1-cea1ad27cca6.png)
(https://codeium.com/)
Individualプランではコードの自動補完、AIチャット、AIコマンドなどが無制限で使える。もちろん、許可されていないデータが学習に使用されることはない。
ちなみに、ProプランはGPT-4oを使う事ができる。

### 対応エディタ
私がCodeiumを勧める理由の一つ。対応エディタがとにかく多い！
以下がその一覧
* Visual Studio
* Visual Studio Code
* Vim
* Jupyter NoteBook   ←!!
* Google Colab
* JetBrains
* NeoVim
* Emacs
* Chrome
* Xcode
* Pycharm
* IntelliJ
* WebStorm
* GoLand
* PhpLand
* CLion
* Android Studio
* Eclipse
* Subline Text

とてつもない多さである。上記の中に、自分が使っているエディタがあったのなら、一度Codeiumを試してみることをお勧めします。

## おわり

いかがでしたか？何かお役に立てたなら嬉しいです。
もしかしたら、この他にもたくさんの無料で使えるエディタがあるかもしれません。今回紹介したもので物足りなかった方は、調べてみるか、それこそ、(エディタではないですが)GenSparkなどのAIを使って調べてみるといいと思います。

## 追記：大前提

無料版より有料版の方が機能的にいいので、お金に余裕がある人は有料版を使いましょう。
【UI Toolkit】Unity6 で UiBuilder 上で Image タグを Library から使用できるように拡張する

# 概要
- Unity6(6000.0.23f1) にて、なぜか Image が UiBuilder の Library に入ってなかったので追加してみました
- 注意: 独自の VisualElement を追加するコードの書き方が Unity6 以前のものだと Obsolated になっているので、以前のバージョンとの互換性はありません
- UI Toolkit よくわからないまま対応してみたものなので、もっといいやり方あるよとか、これだとこういう問題があるよ等のご指摘があると嬉しいです

# 作ったもの

![ui-toolkit-image.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157326/4243b243-8dc7-d10a-f528-267ddac977a6.gif)

# コード全文

```csharp:Image.cs
using UnityEngine;
using UnityEngine.UIElements;

namespace Example.UIElement
{
    [UxmlElement]
    public partial class Image : VisualElement
    {
        [UxmlAttribute]
        public Sprite ImageSprite
        {
            get => _image.sprite;
            set
            {
                _image.sprite = value;
            }
        }

        private readonly UnityEngine.UIElements.Image _image;

        public Image()
        {
            _image = new UnityEngine.UIElements.Image();

            Add(_image);
        }
    }
}
```

# 解説

`UIElements.Image` をラップしておいて、画像更新の窓口だけ Inspector に公開できるようにしてみました。
使うにあたって違和感がないように、同名の `Image` クラス名を採用していますが、干渉しないように名前空間を切りました。

```
[UxmlElement]
public partial class Image : VisualElement
```
`UxmlElement` アトリビュートを partial クラスに追記することによって、UiBuilder の Library に追加できます。

```
[UxmlAttribute]
public Sprite ImageSprite
```
`[UxmlAttribute]` を付与することで、Inspector に追加することができます。

# 参考
- https://light11.hatenadiary.com/entry/2020/04/26/124956
- https://technote.qualiarts.jp/article/19/
- https://www.hanachiru-blog.com/entry/2024/04/04/120000
Azure Data FactoryとGithubの連携

Azure Data Factoryのソース管理をAzure DevOpsではなく、GitHubで行う際の設定内容と挙動について備忘がてらメモ。
Githubとの連携の場合、ユーザーごとにアプリケーション(ADF)の許可の設定が必要なのか不安だったが、結論としては付与だったことが内容の中心

参考：https://learn.microsoft.com/ja-jp/azure/data-factory/source-control#connecting-to-public-github-or-github-enterprise-cloud-for-the-first-time-in-azure-data-factory

# 前提
・Githubに対するコミット、更新権限を所有しているユーザーで設定
・Azure Data Factroyへの共同作成者権限を所有しているユーザーで設定

# 設定方法の概要

①GitHub側Azure Data Factoryに連携するリポジトリを作成し、初期化
③ADF側にて対象のGithubとのリポジトリ連携の設定を実施
https://learn.microsoft.com/ja-jp/azure/data-factory/source-control#azure-repos-settings
　実施の際に、アプリケーション(ADF)に対してGithubの組織へのアクセス許可が必要
　権限に応じて、自信でgrantするか権限がない場合はapply依頼をする
https://learn.microsoft.com/ja-jp/azure/data-factory/source-control#already-connected-to-public-github-or-github-enterprise-cloud-using-a-personal-account


# 懸念していた挙動について
上記設定後に設定したユーザー以外のユーザーがADFを更新する際には、Githubのユーザーごとアプリケーションへの許可が必要となる。
これをいちいち手動で許可設定を行わらないといけないのか、いけないのであれば面倒だと感じていたが
不要だった。厳密にはADFに初回ログイン時(Githubの権限を持っているユーザーという前提)にGithubのログインを求められ、その際に個別に権原がふられる動きのよう
【AtCoder】AtCoderの役に立つかわからない豆知識

# はじめに

競プロerのwhile-true-ifです。今回はAtCoderの役に立つかわからない豆知識を紹介します。

# ABCで過去一難しかった問題(試験管は除く)

## A問題

**diff:103**

A.https://atcoder.jp/contests/abc249/tasks/abc249_a

ただ解くだけ。こういう系が自分は苦手。

## B問題

**diff:511**

B.https://atcoder.jp/contests/abc258/tasks/abc258_b

制約が小さい問題は面倒。この問題はその典型。

## C問題

**diff:1307**

C.https://atcoder.jp/contests/abc307/tasks/abc307_c

この問題はC問300点。300点とは思えない。

## D問題

**diff:1757**

D.https://atcoder.jp/contests/abc288/tasks/abc288_d

この問題はD問400点。青diffで400点は低すぎだと思う。

## E問題

**diff:1970**

E.https://atcoder.jp/contests/abc249/tasks/abc249_e

E問題で制約が`N<3000`のものはやはり裏があった。

## F問題

**diff:3100**

F.https://atcoder.jp/contests/abc313/tasks/abc313_f

赤diffだと読む気がおきない。

## G問題

**diff:3455**

G.https://atcoder.jp/contests/abc330/tasks/abc330_g

転倒数だけ読めた。解説見たらめんどくさそう。

## Ex・H問題

**diff:3884**

Ex.https://atcoder.jp/contests/abc243/tasks/abc243_h

解説がカラーで見やすい。問題はわからないけれど。

# ABCで過去一簡単な問題(試験官は除く)

## A問題

**diff:4**

1.https://atcoder.jp/contests/abc186/tasks/abc186_a
2.https://atcoder.jp/contests/abc202/tasks/abc202_a
3.https://atcoder.jp/contests/abc214/tasks/abc214_a
4.https://atcoder.jp/contests/abc231/tasks/abc231_a

今回は同率が4つあった！全部簡単。

## B問題

**diff:9**

B.https://atcoder.jp/contests/abc222/tasks/abc222_b

これも簡単。B問題から解けばFirstAC狙えるかも。

## C問題

**diff:36**

C.https://atcoder.jp/contests/abc360/tasks/abc360_c

なぜかこの問題で1ペナしている。

## D問題

**diff:129**

D.https://atcoder.jp/contests/abc153/tasks/abc153_d

初心者がこの問題をRatedで解いていたら相当な自信になりそう。

## E問題

**diff:792**

E.https://atcoder.jp/contests/abc294/tasks/abc294_e

E問題唯一の茶diff。茶色コーダーの人がこの問題をRatedで解けたら相当な自信になりそう。

## F問題

**diff:1053**

F.https://atcoder.jp/contests/abc185/tasks/abc185_f

F問題にある2つの緑diffのうちの1つ。

## G問題

**diff:1625**

G.https://atcoder.jp/contests/abc362/tasks/abc362_g

G問題で青色は珍しくていいね！Gは赤色のイメージがある。

## Ex・H問題

**diff:2406**

Ex.https://atcoder.jp/contests/abc259/tasks/abc259_h

ついに暖色来た！なんかうれしい。

# AtCoderの問題構成の変化の歴史

## ABC001~ABC041

試験管マークがあって、4問しかない。

### ABC001

一番最初のコンテスト。4問しかない。

Aから順にdiffが灰・茶・緑・水といい難易度構成。

### ABC002~ABC006

「A問題では、提出した結果、全てのテストに対する判定がWAまたはREになってしまった場合のみ、質問タブにて可能な限りのトラブルシューティングを受け付けます。」と書いてある。やさしい。今やったらAtCoder社の人が大変そう。

### ABC007~ABC041

ABC001とあまり変わらない。

## ABC042~ABC125

4問しかないけど、試験管マークは外れている。このころの制約は`1<=N<=10^5`が多い。

## ABC126~ABC211

6問になった。間違っているかもしれないけれど、ABC152のC問題で`1<=N<=2*10^5`が登場した。問題数以外は今とそっくり。

## ABC212~ABC318

8問になった。自分はABC302から始めたので8問は懐かしい。

## ABC319~

7問に減った。理由はなんだろう？自分にとってはG問題とEx問題には縁がないので今は何も変化を感じない。

## 終わりに

最後まで読んでくれてありがとうございます。リクエストがあったらぜひコメント欄でお願いします。

---

いいねとフォローをしてくれるとありがたいです！
【Ruby】初学者向け－クラスの継承について

本記事ではクラスの継承についてまとめていきます。

目次
・クラスの継承について

<h1>クラスの継承について</h1>

**クラスの継承**
…既存のクラスの機能を新しいクラスに引き継ぎ、再利用や拡張を行うための仕組み。
　共通の機能を親クラス（スーパークラス）にまとめ、子クラス（サブクラス）に継承することができる。


基本のクラス継承の書き方
 ```ruby:example_1.rb

class <親クラス名>
    # 親クラスの定義
end

class <子クラス名>　<  <親クラス名>
    # 子クラスの定義
    # 親クラスとファイルが別でもクラス継承の効果が作用する
end
```
------------------------------------------------
継承の例
 ```ruby:example_2.rb
class Cooking
    def menu
        puts "今日のご飯は#{@food}です"
    end
end

class Food < Cooking
    def initialize(food)
        @food = food
    end
end

# 子クラスであるFoodが親クラスであるCookingを継承しているため、
# 親クラスのメソッドが利用できる。
food1 = Food.new('寿司')
food1.menu
=> "今日のご飯は寿司です"

food2 = Food.new('焼肉')
food2.menu
=> "今日のご飯は焼肉です"
```
----------------------------------

**オーバーライド**
…子クラス内において、親クラスのメソッドと同名のメソッドを定義すると
メソッドの上書きが行えること。

オーバーライドの例
```ruby:example_2.rb
class Cooking
    def menu
        puts "今日のご飯は#{@food}です"
    end
end

class Food < Cooking
    def initialize(food)
        @food = food
    end
    # ここでオーバーライドする
    def menu
        # 親クラスのオーバーライド前のメソッドは「super」の記述で呼び出すことができる
        super
        
        # オーバーライドしたメソッド
        puts "今日の晩御飯は#{@food}です"
    end
end

# 子クラスであるFoodが親クラスであるCookingを継承しているため、
# 親クラスのメソッドが利用できる。
food1 = Food.new('寿司')
food1.menu

# 親クラスの元々のメソッドを使用して返ってきた結果
=> "今日のご飯は寿司です"

# 子クラスで、親クラスのメソッドをオーバーライドしたメソッドを使用して返ってきた結果
=> "今日の晩ご飯は寿司です"

food2 = Food.new('焼肉')
food2.menu

# 親クラスの元々のメソッドを使用して返ってきた結果
=> "今日のご飯は焼肉です"

# 子クラスで、親クラスのメソッドをオーバーライドしたメソッドを使用して返ってきた結果
=> "今日の晩ご飯は焼肉です"
```
ロボットテクノ部　　初投稿

　初投稿になります。

　私たちロボットテクノ部は、プログラミング、電子回路などの作成を行い、様々な大会に出ようと考えてるところです。

![DSC_0980.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3914799/e98e1510-e81b-69e7-9f43-655b803237a8.jpeg)

このあとの、大会で使用するロボットです。
Rails における UserBook.all と UserBook.joins(:user).joins(:book) の違い

# はじめに
中間テーブル `user_books` があったとき、Rails (Active Record) における `UserBook.all` と `UserBook.joins(:user).joins(:book)` の違いについて説明します。



# モデルの定義
以下のようなモデルがあったとします。ユーザは複数の本を所有しており、本は複数のユーザに所有されている、いわゆる多対多の関係になっています。

```ruby
class User < ApplicationRecord
  has_many :user_books
  has_many :books, through: :user_books
end
```

```ruby
class Book < ApplicationRecord
  has_many :user_books
  has_many :users, through: :user_books
end
```

```ruby
class UserBook < ApplicationRecord
  belongs_to :user
  belongs_to :book
end
```



# レコード
以下のようなレコードがデータベースに格納されていたとします。

## `users` テーブル
| id | name |
| :---: | --- |
| 1 | 一郎 |
| 2 | 二郎 |
| 3 | 三郎 |

## `books` テーブル
| id | name |
| :---: | --- |
| 1 | こころ |
| 2 | 三四郎 |
| 3 | 人間失格 |
| 4 | 雪国 |
| 5 | 羅生門 |

## `user_books` テーブル
`user_books` 自体の主キーである `id` は省略します。

| user_id | book_id |
| :---: | :---: |
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
| 3 | 4 |
| 3 | 5 |

上記のテーブルの内容を言語的にまとめると以下のようになります。

* 一郎さんは「こころ」と「三四郎」と「人間失格」を所有している
* 二郎さんは「三四郎」と「人間失格」と「雪国」を所有している
* 三郎さんは「雪国」と「羅生門」を所有している



## ユースケース
「羅生門」は書庫で管理しなくなったなどの理由でレコードを削除したとします。

```ruby
Book.find_by(name: "羅生門").destroy
```

さて、この状態で `user_books` テーブルに存在する、`users` と `books` に紐づいた全レコードを取得したいとします。

以下の Active Record では正しく **取得できません**。

```ruby
UserBook.all
```

なぜなら、`books` テーブルから「羅生門」は削除しましたが、`user_books` テーブルから「三郎さんが羅生門を所有している」という情報は削除されていないからです。

`users` テーブルあるいは `books` テーブルから削除されたレコードが紐づいているものを含まない `user_books` テーブルの全レコードを取得したい場合は以下の Active Record を実行する必要があります。

```ruby
UserBook.joins(:user).joins(:book)
```



# おまけ
逆に `users` テーブルあるいは `books` テーブルから削除されているレコードに紐づく `user_books` テーブルのレコードのみを取得したい場合は以下の Active Record を実行すれば良さそうです。

```ruby
UserBook
  .left_outer_joins(:user, :book)
  .where(users: { id: nil })
  .or(UserBook.where(books: { id: nil }))
```

上記の例でいうとこれは「削除された本『羅生門』を所有しているユーザの情報のみを表示したい」という要件の場合に使用できます。



# 関連するレコードを一緒に削除したい場合
上記の例で `books` テーブルから「羅生門」を削除しましたが、その際に `user_books` テーブルから「三郎さんが羅生門を所有している」というレコードも一緒に消したい場合は該当するアソシエーションに `dependent: :destroy` を付与します。

```diff
class Book < ApplicationRecord
-  has_many :user_books
+  has_many :user_books, dependent: :destroy
  has_many :users, through: :user_books
end
```

これで、`books` テーブルからレコードが削除された際に、そのレコードと紐づいた `user_books` に含まれるレコードも一緒に削除されます。



# 参考
* [ChatGPT - Active Record 中間テーブル 取得](https://chatgpt.com/share/6715f5be-cd9c-8004-b66b-b1cd3a58c001)
* [中間テーブルを用いた処理(Rails) #Ruby - Qiita](https://qiita.com/ysda/items/87c056aed33280995332)
* [【Rails】ActiveRecordでSQLっぽくテーブル結合する方法 #Ruby - Qiita](https://qiita.com/teddy_bear_eng/items/0f7c7723f5d121a493f9)
* [日本文学作品のおすすめ36選。読まれ続けてきた数々の名作をご紹介](https://sakidori.co/article/1324884)
Next.jsでGoogle Analyticsを使うHow to

こんにちは。

`Google analytics`を導入しようとしたところ色んな古い記事に惑わされたので、現時点でのベストプラクティスを記事にまとめます。
まぁ、[公式Doc](https://nextjs.org/docs/messages/next-script-for-ga)が最強って話ですが、公式のライブラリを使うことで、パフォーマンスを犠牲にせず、最短で導入できます。

### 環境

`AWS Amplify`にデプロイしています。

```
next@14.2.15
```

# Google Analyticsの登録

登録はたくさん記事があるのでそれらを参照してください。
`G-XXXXXXXXXX`の`測定ID`が取得できたところからスタートです。

# 導入

本来は`Google Analytics`に表示されるタグをコピペするだけで導入が完了するのですが、`Next.js`だとパフォーマンスの低下を引き起こすので`<Script>`コンポーネントの使用が推奨されています。
ですので、常套手段として検索に引っかかるのは表示されたタグを書き換える手法ですが、**`Next.js`は必要なコンポーネントとスクリプトをタグ一つで導入できるライブラリを提供してくれています。**
これを利用することで面倒な作業無く、タグ一個で導入が完了しコードも見やすくなるので大変におすすめです。

まずはインストールからしていきます。

```
npm i @next/third-parties
```

全てのページに導入するには`app/layout.tsx`にタグを加えます。
`<GoogleAnalytics gaId="G-XYZ" />`を`<body>`タグ内に書き加えます。
`gaId`は自分の測定に書き換えますが、直接書き込むと不都合もあろうので環境変数にします。

```typescript:app/layout.tsx
import { GoogleAnalytics } from '@next/third-parties/google'
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  const gaId: string = process.env.GA_ID || '';

  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleAnalytics gaId={gaId} />
    </html>
  )
}
```

あとは`.env.local`に`GA_ID`を加筆するだけです。

```bash:.env.local
GA_ID=G-XXXXXXXXXX
```

これだけで導入は終了です。
簡単ですね！

# Amplifyでの作業

`AWS Ampllfy`では、環境変数に変数を追加してもビルド時に反映されません。
環境変数として設定した値を、ビルドのシェルに環境変数として渡す必要があります。

まず、`ホスティング > 環境変数`から`GA_ID`という変数名で測定IDを値に登録します。
次に`ホスティング > ビルドの設定`から`amplify.yml`を編集します。
下記のように、`commands`ディレクティブに`Amplify`の環境変数をシェルの環境変数として書き出すコマンドを追記します。

```yml:amplify.yml
version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci --cache .npm --prefer-offline
    build:
      commands:
        - echo "GA_ID=$GA_ID" >> .env
        - npm run build
....
```

これでビルド時に`GA_ID`を利用してビルドしてくれるはずです。

`Google analytics`、サードパーティー製Cookieがなくなるかもと言ってもやはり便利ですよね。
それでは皆さん、よい`Next.js`ライフを！
【学習】静的OGPの設定。


今回は静的OGPというものの実装に挑戦してみたいと思います。

## 環境
- Windows, WSL
- Docker
- Ruby 3.2.3
- Rails 7.1.3


## 理解
リンクをツイッターなどのSNSに貼った時自動でタイトルや画像なんかが表示されていますが、このような表示を可能としているのがOGP。
そして、静的OGPはリンクを貼った時、常に同じ内容。動的OGPはHPのURLや投稿記事URLなど、貼るリンクで表示が変わるもの。

当いう認識で合っているのか:thinking:
記事参考に確認

## 参考記事など
https://github.com/kpumuk/meta-tags

https://qiita.com/suzuyu0115/items/7f83f84b640640b7e498

https://zenn.dev/tteaoocl/articles/4f0fd7189a9fac



## 早速実装
👇`Gemfile`に次の`gem`を追記した後インストール等行います（ファイル作成されますが追記は不要）
```
gem "meta-tags"

$ docker compose run web bundle install
$ docker compose run web rails generate meta_tags:install
      create  config/initializers/meta_tags.rb
```
そして、参考記事をもとに以下を行っていきます
- `application-helper.rb`にOGPの設定を実装していきます
- `app/views/layouts/application.html.erb`に`display_meta_tags`メソッドの追記
- `app/assets/images/ogp.png` に表示したい画像を配置



## 確認方法
参考記事の方にも確認方法は記載ありましたが、おまけで。
- 本番環境のサイトを表示したら右クリック
- Winの場合**ページのソースを表示**をクリック
- `<meta property="og:title" content="ページのタイトル">`のようなOGPタグが正しく設定されているか確認し、あればOK


# 最後にまとめ
「静的OGP」という文字を見ただけで難しそうのイメージを持ち敬遠していましたが、記事を参考に実装してみるとそうでもなかった。
私にもできると知れてよかったです。
今回の記事が何か参考になれば幸いです。