OmniAICreator/Qiita-1.07M huggingface dataset:
APIからGenesysCloud管理画面操作

## 目的
オペレーターさん等に管理画面に入ってもらって、GenesysCloudのリソース変更
してもらいたい場面で、他の画面を触ってしまわないようにCLIからスクリプト起動で操作してもらいたい
ＥＸ）
外部トランクの最大同時コール数の設定等

## Oauthの認証キーを取得

統合>OAuth
より
クライアント ID、クライアント シークレットを取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922935/3f3eccfe-64ad-49f9-baff-8554cd9625b2.png)

クライアント ID、クライアント シークレットからアクセストークンを取得
```
export CLIENT_ID="クライアント ID"
export CLIENT_SECRET="クライアント シークレット"

curl -X POST "https://login.mypurecloud.jp/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET"
```
[各APIのエンドポイント](https://developer.genesys.cloud/platform/ "各種API")

## CLIによる管理画面の変更

変更したいトランクIDを取得
```
curl -X GET "https://api.mypurecloud.jp/api/v2/telephony/providers/edges/trunks" \
     -H "Authorization: Bearer 上記で取得したアクセストークン"
```

下記よりGenesysCloudCLIをダウンロード（本記事ではWindows
[CLIのダウンロードページ](https://developer.genesys.cloud/devapps/cli/ "CLI")

任意の場所に配置し、profiles newで初期設定を行う
※
Client ID:は
GenesysCloudの管理画面（Admin → OAuth）で
作ってある「OAuthクライアント」の「Client ID」を入力する
```
PS C:\CApps> .\gc.exe profiles new
Profile Name [DEFAULT]:
Environment [mypurecloud.com]: mypurecloud.jp
Note: If you provide an access token, this will take precedence over any authorization grant type.
Access Token (Optional):
Select your authorization grant type.
        0. None
        1. Client Credentials
        2. Implicit Grant
        3. PKCE Grant
Grant Type: 1
Client ID: xxxxxxxxxxxxxxxxx
Client Secret:
Would you like to use a proxy server? [Y/N]: N
Would you like to use a gateway server? [Y/N]: N
Profile DEFAULT saved.
PS C:\CApps>
```

↑で取得したトランクIDを指定し変更
```
.\gc.exe telephony providers edges trunkbasesettings update $trunkId
```
psファイルにするなら↓
```
param (
    [int]$newMaxCalls
)


# trunk設定に使うID

$trunkId = "xxxxx"


# 一時的なjsonファイルパス

$tempJson = ".\temp_trunk.json"


# 現在の設定を取得して保存
.\gc.exe telephony providers edges trunkbasesettings get $trunkId | Out-File -Encoding utf8 $tempJson


# jsonを読み込み

$json = Get-Content $tempJson | ConvertFrom-Json


# trunk_maxCalls_trunkbaseが存在するかチェック
if ($null -ne $json.properties.trunk_maxCalls_trunkbase) {
    # 書き換え
    $json.properties.trunk_maxCalls_trunkbase.value.instance = $newMaxCalls

    # 上書き保存
    $json | ConvertTo-Json -Depth 10 | Out-File -Encoding utf8 $tempJson

    # 更新実行
    .\gc.exe telephony providers edges trunkbasesettings update $trunkId -f $tempJson

    Write-Host "Done. Set max calls to $newMaxCalls"
}
else {
    Write-Host "trunk_maxCalls_trunkbase not found."
}
```
スタックを使った逆ポーランド記法計算機を作ってみた

# はじめに
こんにちは、kuwaです。

本記事では、C言語による **スタック を利用した逆ポーランド記法（RPN: Reverse Polish Notation）** のサンプルコードを紹介します。

> ⚠️ 本記事は個人的な学習メモとして作成したものであり、内容に誤りが含まれている可能性があります。参考にされる際はご注意ください。


## スタックと逆ポーランド記法

**逆ポーランド記法（RPN）** とは、演算子をオペランドの「後」に記述する記法です。

### 例：
中置記法（一般的な記法）での数式：
```
(1 + 2) * (5 + 4)
```

逆ポーランド記法では：
```
1 2 + 5 4 + *
```

この記法では、**括弧を使わなくても式の順序が明確になる**という利点があります。

RPNの評価には「**スタック**」というデータ構造が非常に適しており、オペランドをスタックに積み、演算子が出てきたら上から2つを取り出して演算し、結果を再びスタックに積むことで実現できます。


## 入出力仕様

### 入力

1つの数式が1行で与えられます。  
数式は、オペランド（数値）および演算子（`+`、`-`、`*`）からなり、**空白区切り**で構成されます。

### 出力

計算結果を1行で出力してください。

---

## 制約

- 2 ≤ 式に含まれるオペランドの数 ≤ 100  
- 1 ≤ 式に含まれる演算子の数 ≤ 99  
- 演算子は `+`, `-`, `*` のいずれか  
- 各オペランドは `10^6` 以下の正の整数  
- 計算途中および最終結果の範囲：`-1×10^9 ≤ 値 ≤ 1×10^9`

---

## 入出力例

#### 入力例 1
```
1 2 +
```
#### 入力例 1 に対する出力
```
3
```
#### 入力例 2
```
1 2 + 3 4 - *
```
#### 入力例 2 に対する出力
```
-3
```
## サンプルコード



```c
#include <stdio.h>
#include <stdlib.h>

#define STACK_SIZE 100 //オペランドの数が100以下なのでスタックのサイズは100

int stack[STACK_SIZE];
int top = 0;

void push(int x) {
    stack[++top] = x; //前置インクリメント．top++;の後にxを代入する
}

int pop() {
    return stack[top--]; //後置インクリメント．returnの後にtop--;
}

int main(void) {
    char s[100];
    while (scanf("%s", s) != EOF) {
        if (s[0] == '+') {
            int b = pop();
            int a = pop();
            push(a + b);
        } else if (s[0] == '-') {
            int b = pop();
            int a = pop();
            push(a - b);
        } else if (s[0] == '*') {
            int b = pop();
            int a = pop();
            push(a * b);
        } else {
            push(atoi(s));
        }
    }

    printf("%d\n", pop());
    return 0;
}
```
【SwiftUI】トラッキングの取得タイミングに注意しよう

# リクエストはアプリがActiveになってから行う
トラッキングのリクエストはアプリがActive状態になってから呼び出さないと表示されない。

> Calls to the API only prompt when the application state is UIApplicationStateActive.
https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/requesttrackingauthorization(completionhandler:)

# ViewがActiveになるタイミング
アプリ起動直後にリクエスト行う場合、AppDelegateクラスが元々ある場合は`didFinishLaunchingWithOptions`に直接定義することが多いと思う。
しかしAppDelegateがない場合はSwiftUIのView内の`.onAppear`や`.task`に定義しようと考えてしまうが、それだとリクエストのAlertが表示されない。

というのも、`.onAppear`の次に`.task`が呼ばれ、その後にアプリがActive状態になるためである。

```Swift
import SwiftUI

struct ContentView: View {
    
    @Environment(\.scenePhase) private var scenePhase
    
    var body: some View {
        EmptyView()
            .onAppear {
                print("onAppear")
            }
            .task {
                print("task")
            }
            .onChange(of: scenePhase) {
                if scenePhase == .active {
                    print("active")
                }
            }
    }
}
```
↓実行結果
```
onAppear
task
active
```
なので`.onAppear`, `task`にリクエストを定義しても、まだActive状態になっていないのでアラートが表示されない。

# 正しい取得タイミング
ということでscenePhaseがactiveになったタイミングでリクエストすればいい。

```Swift
import SwiftUI
import AppTrackingTransparency

struct ContentView: View {
    
    @Environment(\.scenePhase) private var scenePhase
    
    var body: some View {
        EmptyView()
            .onChange(of: scenePhase) {
                if scenePhase == .active {
                    Task {
                        guard ATTrackingManager.trackingAuthorizationStatus == .notDetermined else { return }
                        _ = await ATTrackingManager.requestTrackingAuthorization()
                    }
                }
            }
    }
    
}
```

info.plistへの定義も忘れずに。
![スクリーンショット 2025-05-26 12.34.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237700/08895759-b357-43aa-a2cf-1077530ee992.png)

# 最後に
自分も`.onAppear`や`.task`に定義して少しだけ遅延させて表示させていたが、上記の方法が正しそう。
あとSwift6で`requestTrackingAuthorization`のcompletionの方を呼ぶとクラッシュするというのを見たが、クロージャ内で@Sendableを付与すると回避できる。でも普通にasyncの方を使うので良さそう。
```Swift
ATTrackingManager.requestTrackingAuthorization { @Sendable status in
    print(status)
}
```
社員インタビュー｜スキルアップが止まらない！～PHP+JSを駆使する私の軌跡～

![note.：社員インタビュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4093365/abc21610-62cc-4b3b-a1c5-c77c13631b6c.png)


今回は株式会社グラディートで活躍する、開発エンジニアさんにお話を伺いました。
お話いただいたのは、PHP＋JSを得意分野とするS.Tさん。
エンジニアという職業にずっと憧れがあり、その夢を叶えた努力家です！

そんなS.Tさんに、エンジニアを目指した経緯や、会社の魅力、今後の展望について伺いました。
是非、ご覧下さい！

# 自己紹介
私はごく普通の高校を卒業し、その後しばらくフリーターとして居酒屋でアルバイトをしていました。
のちに、入社後一定期間内にSQLの資格を取ることができれば正社員として入社できる会社へ応募し、無事資格を取得したことでエンジニアとしてのキャリアがスタートいたしました。
未経験だったこともあり、苦労もありましたが自習を含め積極的に技術を学び今に至ります。

# 生い立ち
千葉県のとある田舎にて育ち、広大な畑をもつ友人などもおり、幼少期は外で遊ぶ事が好きな子供でした。
中学校まで野球を続け、高校では軽音楽部のヘルプをするなど、友人に恵まれたと感じています。
現在は実家に戻っており、田舎ゆえの静かさを実感しております。

![画像1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4093365/ebaab874-0fc4-4b38-b60b-1230f36d7f83.jpeg)

# 得意分野（言語）
PHP+JSの開発を得意としています。
どちらもフレームワークを3種扱うことができ、様々な案件で活用できることを願うと同時に、器用貧乏にならないように、また習得した技術を錆びさせないように日々学習を心掛けております。

# エンジニアを目指したきっかけ
幼少期の時分では、子供がPCを持つ環境がまだ珍しい時代でしたので、その時期にPCに触れた事は確実に今につながっていると考えています。
前述の通りフリーター時代は居酒屋でアルバイトをしていましたが、正社員を目指すとして得意な事は何かと考えた時に真っ先に思い当たったのがPCを扱う職業で、プログラマを目指したのは最初は憧れからでした。
実際にプログラマとして働いてみてしっくりきたというのが正直な感想ですので、憧れが叶ったと言えるのかもしれません。

# 現在の仕事
主に業務系WEBプログラムの改修や、ECサイトの改修などをおこなっております。
同じような案件であっても、採用されている技術やツールが異なることは多々あるため、都度学習を心掛けております。

# 仕事で一番大切にしていること
私が大切にしていることは、 **常に技術の習得を心掛けること**で、どのような案件であっても自分が知らない技術や知見などは確実にあり、そこを進んで習得するという気概を持つようにしております。

# プライベートの過ごし方
普段プライベートでおこなっていることを取り上げるとすると、料理や楽器、キャンプなどが挙げられます。
特にキャンプについては秋冬のみ行きますが、焚火をのんびり眺めるのが好きで、ついグッズも買いあさってしまいました。


![画像2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4093365/fe8db680-5231-4986-a8e2-3863ce1c4e30.jpeg)


# エンジニアとしての誇り
まず一つとして、 **常に最新のトレンドに目を向ける**よう心掛けています。
技術関連のサイトを覗くほか、今も付き合いのある元同僚と議論を交わすなどして、知見を深めております。
また次に、常に自習、自学を心掛けており、現在はスキルの棚卸しのようなWEBプログラムをプライベートで作成しております。
上記を通じて、結果的にお客様の望む高い品質の技術を提供できればと考えております。

# これから挑戦したいこと
ITという分野では無限に技術があり、全体から見ると今の自分ができることはごく限られていると考えております。
ですので、できる限りできることと未だ出来ずにいることとのギャップを減らし、その反復を長く続けていくことができればと考えております。

# グラディートに対しての感想
案件に対する情報をはじめ、IT業界全体に関する知見など様々な情報を共有いただけるため、自分の知らなかった分野でこのような事情があり、このようなことが起きているのだなということがわかり、とても刺激的に感じます。
また新入社員として感じたのはメンバーの方々が気さくに相談を促していただけることで、最初あった不安が各段に楽になりました。

# 転職を考えている方へのメッセージ
 **自分の価値が正確に測られること、そしてそれを形として還元してくれる会社**であると私は考えております。
チャレンジし続けるマインドを持っている方はきっと評価されると思います！

# 安心安全のホワイト高還元SESに転職を考えている方へ
新しい挑戦に踏み出すことは、人生において重要な一歩です。
転職活動は自分自身を知り、成長する貴重な機会でもあり、夢や成長を追求するためには必要な要素の一つになるかと思います。
どんな選択をされるにせよ、その決断があなたに取って素晴らしい未来を切り開くことを願っています！
グラディートと一緒に誇れるエンジニアを目指しましょう！

■『株式会社グラディート』では受託開発・SES・ブランディングデザイン・事業コンサルティングなどを事業として行う都内のIT企業です。現在、不遇な待遇で困っているエンジニアさんは、ぜひ一度グラディートに相談してみてね！（年収査定・SESへの転職相談も承っております！）

株式会社グラディート採用情報はこちら▼
https://en-gage.net/gradito/

株式会社グラディート公式サイトはこちら▼
https://www.gradito.co.jp/
🛍️ Java入門：抽象クラスで「商品情報を表示するプログラム」をシンプルに設計しよう！



## ✅ この記事で学べること

- Javaの**抽象クラス**の基本  
- 商品カテゴリごとの**表示内容のカスタマイズ**  
- 実際の**ショッピングサイト風コード**で学ぶオブジェクト指向  

---

## 🔧 抽象クラスとは？

抽象クラスとは、  
**直接インスタンス化はできないが、共通のふるまいを定義できる設計用のクラス**です。

### ✍️ 特徴

- `abstract` キーワードを使う  
- インスタンス化できない  
- **共通メソッド**は中身を実装してもOK  
- **抽象メソッド**（実装なし）はサブクラスで実装が必須  

> 💡「どうして使うの？」と思う方のために、次章で具体例を見ていきましょう！

---

## 📦 ショッピングサイトを題材に学ぼう！

とあるショッピングサイトで「商品情報を表示するプログラム」を作るとします。

### 📝 要件

**共通処理**
- 商品ごとに、画面上部に「-------------」を表示（区切り線）

**個別処理**
- 食品：原産地、消費期限を表示  
- 衣料品：製造地、サイズを表示  

### 🖥️ 出力イメージ

```

---

原産地：青森県
消費期限：2025/5/5
-------------

製造地：日本
サイズ：M

````

> このようにカテゴリごとに表示内容が異なる場合、**抽象クラスを使って共通処理と個別処理を分離**するのがオススメです！

---

## 🧩 抽象クラス `Product` の定義

```java
// Product.java
public abstract class Product { // 抽象クラス

    // 各サブクラスで実装すべきメソッド
    public abstract void showInfo(); // 抽象メソッド

    public void msg() {
        System.out.println("-------------"); // 共通処理①
        showInfo(); // サブクラスで個別に実装された処理を呼び出す②
    }
}
````

---

## 🍎 食品クラス `Food`

```java
// Food.java
public class Food extends Product {

    @Override
    public void showInfo() {
        System.out.println("原産地：青森県"); // 個別処理③
        System.out.println("消費期限：2025/5/5"); // 個別処理④
    }
}
```

---

## 👕 衣料品クラス `Clothing`

```java
// Clothing.java
public class Clothing extends Product {

    @Override
    public void showInfo() {
        System.out.println("製造地：日本"); // 個別処理⑤
        System.out.println("サイズ：M"); // 個別処理⑥
    }
}
```

---

## ▶ 実行用コード（`Main.java`）

```java
// Main.java
public class Main {
    public static void main(String[] args) {
        Product apple = new Food();
        Product tshirt = new Clothing();

        apple.msg();   // Product① + Product②（Food③ + Food④）
        tshirt.msg();  // Product① + Product②（Clothing⑤ + Clothing⑥）
    }
}
```

---

## ✅ 実行結果

```
-------------
原産地：青森県
消費期限：2025/5/5
-------------
製造地：日本
サイズ：M
```

---

## 💡 ポイント解説

| クラス名       | 処理内容                                   |
| ---------- | -------------------------------------- |
| `Product`  | ① 区切り線表示 + ② `showInfo()` の呼び出し（実体は未定） |
| `Food`     | ③ 原産地の表示 + ④ 消費期限の表示                   |
| `Clothing` | ⑤ 製造地の表示 + ⑥ サイズの表示                    |
| `Main`     | それぞれのインスタンスに `msg()` を実行し共通＋個別処理を呼び出す  |

---

## ✅ まとめ

* **抽象クラスを使えば、「共通処理」と「個別処理」をスッキリ分離**できます。
* オブジェクト指向の原則に沿って、「食品は原産地と消費期限」「衣料品は製造地とサイズ」というカテゴリごとの振る舞いをわかりやすく実装できます。
* 新しいカテゴリ（例：家電、雑貨など）が増えても、`Product` を継承すれば簡単に拡張可能！

---

## 🔁 次にやってみよう！

* 新しいクラス（例：Electronics）を追加して、保証期間などを表示してみる
* 商品情報をリストで管理し、繰り返し表示するロジックを追加してみる

---

📚 **Javaの抽象クラスをマスターして、読みやすく拡張しやすいコードを目指そう！**
【AWSハンズオン】AWS業務未経験者がEC2 ×2台＋ALB構成を構築してみた

## 自己紹介
・オンプレの保守を約３年間経験
・AWS CLF,SAA取得はしているもののクラウドを使った業務は完全未経験

オンプレミスの複雑な構成をリモートで管理できるAWSに魅力を持ち認定資格取得をしました。
現在は転職活動中で勉強によって得た知識をアウトプットしてきたいと考えたのが今回投稿をした動機です。

## 今回実施した構成概要

- EC2 ×2台（Web1 / Web2）
- Apache + index.html をインストール
- Application Load Balancer（Internet-facing）
- セキュリティグループを ALB / EC2 で分離

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4097535/466e51e9-95f5-4a21-9484-0ab15ddc6e20.png)


## なぜこの構成を試したのか

実務に近い構成だから。
それに、ずっと資格取得のために勉強していたので
実機でどんな挙動をするのかとか。色々試してみたかったんですよね笑

## 参考にしたツール
・ChatGPTのみ

## 今回のゴール

 HTMLにそれぞれ「This is Web1」「This is Web2」みたいな文言を書いて
リロードで切り替わるのが見えるようにすること。


## 実施した手順

① EC2作成

➁セキュリティグループの設定

③ターゲットグループ、ALBのリスナー設定


## 実施した感想
EC2の作成からセキュリティグループの設定まで実施したのは
初めてだったのでとにかく変な料金が発生しないかで怖かったですね笑
HTMLのページをリロードして切り替わった瞬間は感動しました笑

実施していく過程で詰まったポイントがいくつかあるので紹介します。

## セキュリティグループの設定

Webサーバ１とWebサーバ２のHTMLページ単体では問題なく
表示されていました。しかし、ALBのドメインをアドレスに打ち込んでも
切り替え以前にページが全く表示されなかったのです。


その原因は、、

**EC2とALBに全く同じセキュリティグループを付与してしまっていたこと。**

最初は他に問題があると思い、

- VPCにIGWがちゃんと付与されているか
- Apacheがポート80を待ち受けているのか。
- ターゲットグループの状態がHealthyになっているか。
- ALBのスキームが Internet-facing か？

上記を全て確認したけど解決しない。
まさか、セキュリティグループに問題があるとは、、

この問題に気がつくのに1~2時間がかかりました笑
何事も一つの作業にハマると視野が狭くなりますよね～～～泣
しかし問題はまだ続きます。


EC2用のセキュリティグループを作成し付与した後、
リロードを試すも、、

**ページが表示されない**

次は何ぞやと思っていたら、、

## アウトバウンドルールが未設定（＝空っぽ）

そりゃ通信できねえわ、、笑笑
本当になにしてんだよ自分と思いながら
アウトバンドルールを追加して実施したら無事表示されました。

## 表示されたときの感動は計り知れない
ページが表示されたときは本当に感動しました。
それと同時にセキュリティグループの重要性を痛いほど知らされたし
非常にためになりました。

## 次に試したいこと
これら上記の作業をIacを利用して自動化してみたいです。

**「楽」**

これに越したことはないので、、笑

AWSの資格試験の勉強記録について記載できればともかんがえています
末尾だけど、末尾じゃなくても追加可能な.pushメソッド

### `.push`メソッドとは
- 配列末尾への要素追加を行う破壊的メソッド  
- 呼び出し先の配列を直接書き換え、**変更後の配列自身**を戻り値として返す
```ruby
num = [1, 2, 3]

num.push(4)

num　　# => [1, 2, 3, 4]
# 元の変数numが書き換えられている破壊的メソッドであることがわかる（後述）
```

### 基本的な使い方
① 空の配列に任意のオブジェクトを（複数）追加する場合
```ruby
number = []
x = 123
y = 456

number.push(x, y)

number　# => [123, 456]
```

② 配列をそのまま要素として追加する場合
```ruby
arr = []

arr.push([x, y])

arr　　# => [[123, 456]]
```

---
### 特徴
- **可変長引数に対応**
　- 複数の要素を一度に末尾へ追加可能
```ruby
array = [1]

array.push(2, 3)

array　　# => [1, 2, 3]
```

- **破壊的メソッド**
　- 元の配列を直接書き換える
　- 戻り値は変更後の配列になる
 ※ 通常、破壊的メソッドは末尾に ! が付くが、push は例外

- 他の挿入方法あり
　- 例：`array << obj`
　- ただし、単一の要素のみ追加できる

### 覚書
- 「**末尾**！！！！」ではなくても、空の配列を作ってただただ要素を追加可能
（基本的な書き方①）
```ruby
str = []
a = "Pokemon"

str.push(a)

str  # => ["Pokemon"]
```

---
### まとめ
- 「**末尾**！に要素を追加」の**末尾感が強すぎる**印象が個人的にあるが、空の配列を作って要素を挿入する時にも全然使える。
- `<<`ではなく、`.push`を使えば良さそう。
- 大は小を兼ねる。
C言語で挿入ソートを実装してみた

## はじめに
こんにちは、kuwaです。

本記事では、C言語による **挿入ソート（Insertion Sort）** のサンプルコードを紹介します。

> ⚠️ 本記事は個人的な学習メモとして作成したものであり、内容に誤りが含まれている可能性があります。参考にされる際はご注意ください。


## 挿入ソートとは？
挿入ソート（Insertion Sort）は、手持ちのトランプを並び替えるときに自然に使われるような、直感的でわかりやすいソートアルゴリズムのひとつです。

具体的には、次のような操作で並べ替えを行います：

> 1枚ずつカードを取り出して、それをすでに並んでいるカードの中の正しい位置に挿入する。

この操作を繰り返すことで、全体を昇順に並び替えることができます。




##  入出力仕様
### 入力
最初の行に、数列の長さを表す整数 N が与えられます。
次の行に、N 個の整数（数列の要素）が空白区切りで与えられます。

### 出力
挿入ソートの各ステップにおける配列の状態を、それぞれ1行で出力してください。
配列の要素は、各行とも空白区切りで出力します。ただし、行末に余分な空白を入れないように注意してください。余分な空白や改行があると Presentation Error になる可能性があります。

## 制約

- 1 ≤ *N* ≤ 100
    
- 0 ≤ 各要素 ≤ 1,000

## 入出力例
#### 入力例 1
```
6
5 2 4 6 1 3
```
#### 入力例 1 に対する出力
```
5 2 4 6 1 3
2 5 4 6 1 3
2 4 5 6 1 3
2 4 5 6 1 3
1 2 4 5 6 3
1 2 3 4 5 6
```
#### 入力例 2
```
3
1 2 3
```
#### 入力例 2 に対する出力
```
1 2 3
1 2 3
1 2 3
```
## サンプルコード



```c
#include<stdio.h>
#define MAX_N 100


int arrayScan(int *a) //整数ｎ，ｎ個のデータをスキャン，ｎを返す
{
    int n;
    int i;
    scanf("%d", &n);
    for (i=0; i<n; i++) {
        scanf("%d", &a[i]);
    }
    return n;
}

void arrayPrint(int n, int *a) {
    int i;
    for (i=0; i<n-1; i++) {
        printf("%d ", a[i]);
    }
    printf("%d\n", a[i]);
}

void insertionSort(int *a, int n) {
    int i;
    for (i=1; i<n; i++) {
        int v = a[i];
        int j=i-1;
        while (j >= 0&& a[j] > v) {
            a[j+1] = a[j];
            j--;
        }
        a[j+1] = v;
        arrayPrint(n, a);

    }

}

int main(void) {
    int n;
    int a[MAX_N];
    n = arrayScan(a);
    arrayPrint(n, a);
    insertionSort(a, n);
    return 0;
}
```
Obsidianの改ページを見える化する方法

# 何が問題か

Obsidianでは、マークダウン内の改ページしたいところで
以下のタグを挿入すれば改ページができます。

```html
<div style="page-break-after: always;"></div>
```

ただ、これマークダウンプレビュー時には空のdivタグなので何も表示されず、
後でどこに改ページを仕込んだか間違いなく忘れてしまいます。

これでは、メンテナンス性が良くないですよね。

ということで、Wordpressのように、
改ページを仕込んだ場所を見える化します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/c7161f52-a650-4a02-aeaa-59eb697d0152.png)

もちろん、印刷時(PDF出力時)にはこのラベルは表示されず、
単に改ページとして機能します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/af570764-7454-4329-9460-ca6ec82f288b.png)


備考: Better Export PDFのPDFプレビューで見ると、改ページが機能しません。
しませんが、実際にPDF出力すれば、ちゃんと改ページされているのでご安心ください。

# 実装

これをObsidianのカスタムCSSスニペットに追記 or 新規作成してください

設定 > 外観 > CSSスニペット

```css:/Obsidian Vaults/.obsidian/snippets/pagebreaks.css
/* 改ページ用divの表示設定 */
div[style*="page-break-after: always"] {
    border-top: 2px dashed #888;
    margin: 1em 0;
    position: relative;
}

div[style*="page-break-after: always"]::before {
    content: "[page break]";
    position: absolute;
    top: -0.8em;
    left: 50%;
    transform: translateX(-50%);
    background-color: var(--background-primary);
    padding: 0 1em;
    color: #888;
    font-size: 0.9em;
}

/* 印刷時には視覚的表示を無効化 */
@media print {
    div[style*="page-break-after: always"] {
        border-top: none !important;
        margin: 0;
    }

    div[style*="page-break-after: always"]::before {
        content: "";
        display: none;
    }
}
```

# 追記

見える化すると、嬉しい副産物がありました。
改ページ部分をクリックすると、HTMLが編集できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/b1c2418a-c6eb-4b36-9bc1-00063d08577a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/16cde843-e6e1-4dfe-baf6-8cc40899165f.png)

これで、改ページを別の場所にコピペするのも簡単になりますね。

# 参考サイト

https://qiita.com/hann-solo/items/7746c44f7fed2944045d

https://gist.github.com/liamcain/81679412643690a7cdd13dff4dc909ce
【rails】devise で独自のカラムを追加する方法


## はじめに

こんにちは。アメリカ在住で、独学でエンジニアを目指している Taira です。
現在 Rails アプリを devise を用いて作成しています。
前回は devise の導入方法についての記事を書きましたが、devise を使うことであらかじめ `email` や `encrypted_password` などのカラムが与えられます。
しかし、name や username 等の独自カラムを追加したい場面も多いでしょう。
そこで本日は devise で独自カラムを追加する方法について解説します。

## 前提

まず、以下のコマンドで devise の user モデルを作成します。

```bash
bin/rails generate devise User
```

このコマンドで User モデルとマイグレーションファイルが自動生成されます。

生成された db/migrate/TIMESTAMP_devise_create_users.rb を開き、name や username など追加したいカラムを追記します。

```ruby
class DeviseCreateUsers < ActiveRecord::Migration[8.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :name, null: false # 追加
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      # ...（省略）
      t.timestamps null: false
    end
    # ...（省略）
  end
end
```

上記に name を追加したら、以下でマイグレーションを適用します。

```bash
bin/rails db:migrate
```

正常に追加できていれば、`db/schema.rb` の users テーブルに name が含まれていることを確認してください。

```ruby
create_table "users", force: :cascade do |t|
  t.string "name", null: false # 追加されていることを確認
  # ...（省略）
end
```

## このままだと何が問題なのか？

devise のコントローラーは初期状態では `email` や `password` しか許可していません。
そのため、signup 画面で name を送信しても保存されません。
独自カラム（例: name）をフォームから保存できるようにするには strong parameters の追加設定が必要です。

ここでは signup（registrations コントローラ）への追加方法を紹介します。

### Devise コントローラーのカスタマイズ

まず devise のコントローラーを生成します。

```bash
rails generate devise:controllers users
```

次に `app/controllers/application_controller.rb` に `configure_permitted_parameters` メソッドを追加します。

```ruby
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end
```
`configure_permitted_parameters`はストロングパラメータを指しており、deviseで自分で作成したカラムを追加してサインインの時に使用したいときは`application_controller.rb`にまとめて書いておくことが一般的なようです。


### 動作確認

これでサインアップ時やプロフィール編集時に name カラムが保存されるようになります。
画面や rails console で name が登録できているか確認しましょう。

## 参考資料

https://github.com/heartcombo/devise
Laravel Intervention Image使えない場合の代案(リサイズとwebp変換等)

# 課題
Laravelプロジェクトで画像処理に [Intervention Image](http://image.intervention.io/) を導入しようとしても、  

```bash
Class Intervention\Image\ImageManager not found
```
のようなエラーになる可能性がある。 LaravelのServiceProviderによるバインドが適切に行われていない、あるいはIntervention Imageのバージョン違いによるものである。
特に Intervention Image v3系 では、従来の Image::make() のような使い方ができなくなっており、明示的にドライバを指定する新しい書き方が必要になる。

ここでは、自前で軽量に画像のリサイズと WebP 変換を行うユーティリティクラスを作成する方法を紹介する。

# 対応方法
```bash
use Intervention\Image\Facades\Image;
```
の代わりに以下の書き方でうまくいった。

```bash
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\Encoders\WebpEncoder;
```

このように、ImageManager を new でインスタンス化し、明示的に Gd ドライバを指定して使います。これにより、LaravelのServiceProviderに依存せずで使用可能となる。
これでリサイズとWebP変換を実装する。

# 具体例

```bash
<?php
namespace App\Utils;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\Encoders\WebpEncoder;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Carbon;

class ImageUtil
{
    public static function imageUpload($file, string $dir, ?string $name)
    {
    // 省略
    }

    private static function convertToWebP($file)
    {
        // GDドライバを使って ImageManager を初期化
        $manager = new ImageManager(new Driver());

        // アップロードされた画像ファイルを読み込む
        $image = $manager->read($file);

        // WebP形式へのエンコーダを作成
        $webpEncoder = new WebpEncoder();

        // WebP形式にエンコード
        $webpImage = $image->encode($webpEncoder);
        
        return $webpImage;
    }

    private static function resizeImage($file)
    {
        // GDドライバを使って ImageManager を初期化
        $manager = new ImageManager(new Driver());
        
        // アップロードされた画像ファイルを読み込む
        $image = $manager->read($file);
        
        // 画像を最大1920x1080にリサイズ（アスペクト比は保持される）
        $image->scaleDown(width: 1920, height: 1080); 
        
        return $image;
    }
}
```



[参考]
* https://github.com/Intervention/image/issues/1238#issuecomment-1850071158
* https://stackoverflow.com/questions/77750261/laravel-class-intervention-image-not-found
* https://qiita.com/__developer__/questions/78854b86f9d39e1f478e
* https://qiita.com/masuda-sankosc/items/874f6128de29ece021d5
Vue3 の ref・computed・const の使い分け

Vue 3（Composition API）では、`ref`、`computed`、`const` をそれぞれ使い分けることで、状態管理や画面表示をシンプルに書くことができます。

この記事では、それぞれの役割と使い分け方を個人的なノートとして残しています。

---

## 結論：使い分けの早見表

| 目的                 | 使うべき型        | 説明                           |
| ------------------ | ------------ | ---------------------------- |
| 値をUIとリアクティブに連動させたい | `ref()`      | 入力欄やボタンなど、値の変化に応じてUIを更新するため  |
| 他の値に依存した計算結果を表示したい | `computed()`　　　 | 元の値が変化したら、自動的に再計算されてUIを更新    |
| 一度だけ使う定数や固定値       | `const`      | UIと連動しない、変化しないデータ。単なる定数などに使う |

---

## `ref`：リアクティブな「箱」

Vueに「この値の変化を監視してほしい」と伝えるのが `ref()`。

```ts
import { ref } from 'vue'

const name = ref('')
```

テンプレートでは `.value` を省略して使えます：

```vue
<template>
  <input v-model="name" />
  <p>こんにちは、{{ name }}さん！</p>
</template>
```

ユーザーが入力した文字が `name` にリアルタイムで入り、それが画面に反映される、というのが Vue の強みです。

---

## `computed`：他の値に依存する計算結果

`computed()` は、ある `ref` や `reactive` な値に基づいた**派生的な値**を計算するために使います。

```ts
const count = ref(1)
const double = computed(() => count.value * 2)
```

この `double` は `count` が変わるたびに再計算されます。

テンプレートではそのまま使えます：

```vue
<p>カウントの2倍：{{ double }}</p>
```

※ここで `ref` を使って `const double = ref(count.value * 2)` のようにしてしまうと、一度しか計算されず、`count` が変わっても更新されません。要注意。

---

## `const`：固定値や非リアクティブなデータに使う

リアクティブにする必要がない「定数」や「一度だけ表示する文字列」には `const` を使います。

```ts
const title = 'Vue 3 入門'
```

たとえば、ページタイトルや固定のラベル文など。

テンプレートでもそのまま使えます：

```vue
<h1>{{ title }}</h1>
```

---

## よくある間違い

### ❌ `ref`を使わずに変数を定義する

```ts
// これはVueにとってリアクティブではない
let name = ''
```

これでは `name` の変化をVueが検知できません。

→ UIと連動したいなら必ず `ref()` を使う。

---

### ❌ `ref` を計算処理に使う

```ts
// ❌ 非推奨：countが変わってもdoubleは変わらない
const double = ref(count.value * 2)
```

→ 正しくは：

```ts
// ✅ 推奨：computedで自動再計算
const double = computed(() => count.value * 2)
```

---

## まとめ

* ユーザー入力やクリックに反応させたい → `ref`
* 他の値に基づく計算を自動で行いたい → `computed`
* 変化しない定数やUIと無関係な値 → `const`

この3つを使い分けることで、Vue 3 のコードはよりシンプルで直感的になります。

---

以上が `ref` / `computed` / `const` の基本的な使い分けになります。
SeleniumのWebElementの出現をauto-waitingする

## はじめに

やりたいことは、Playwrightのように、ロケータで指定した要素が出現するまで待機する([auto-waiting](https://playwright.dev/docs/actionability))ことです。
SeleniumのWebElementは、要素が見つからない場合に例外を投げるため、通常のコードでは自動的に待機しません。
そのため、要素が出現するまで待機するためのラッパーをPage Object Modelの設計パターンに組み込んでで実装します。

## 環境

- Python: 3.13
- Selenium: 4.32.0
- Appium: 2.18.0

## 実現方式

[Explicit waits](https://www.selenium.dev/documentation/webdriver/waits/#explicit-waits)に記述された`WebDriverWait`を使用して、要素が出現するまで待機します。
`WebDriverWait`は、指定した条件が満たされるまで待機するためのクラスです。条件には、要素が存在することや、要素がクリック可能であることなどがあります。
ここでは、要素が出現するまで(visibleになるまで)待機するために、`expected_conditions`モジュールの`visibility_of_element_located`を使用します。

## 実装

### 基底クラス

以下に示すクラスを継承して、Page Object Modelのクラスを実装します。
`Model.find_element`メソッドは、指定したロケータで要素を検索し、要素が出現するまで待機します。

```python:base.py
from selenium.webdriver.support.expected_conditions import visibility_of_element_located,
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.ui import WebDriverWait


class Model:
    def __init__(self, driver: WebDriver, timeout: float = 10.0) -> None:
        self.driver = driver
        self.wait = WebDriverWait(driver, timeout)

    def find_element(self, locator: tuple[str, str]) -> WebElement:
        return self.wait.until(visibility_of_element_located(locator))

    def __getattr__(self, name: str) -> WebElement:
        if hasattr(self.__class__, name.upper()) and isinstance(getattr(self.__class__, name.upper()), tuple[str, str]):
            locator = getattr(self.__class__, name.upper())
            return self.find_element(locator)
        raise AttributeError(f"'{self.__class__.__name__}' has no attribute '{name}'")
```

### 継承クラス

`Model`クラスでは、[`object.__getattr__`](https://docs.python.org/ja/3.13/reference/datamodel.html#object.__getattr__)をオーバーライドしています。
`Model.__getattr__`メソッドは、「呼び出されたクラス属性名をすべて大文字にした変数を`Model.finde_element`メソッドに渡し、その返り値をクラス属性として返す」と定義しています。言い換えれば、ロケータをクラス変数としてあらかじめ定義し、それらのロケータが指す要素(`WebElement`)をクラス属性として取得できるようにしています。
例えば、以下の`LoginPage`クラスの`USERNAME`、`PASSWORD`, `LOGIN_BUTTON`のクラス変数は、ロケータ(`tuple[str,str]`)を表し、これらのロケータに該当する`WebElement`を`username`、`password`、`login_button`のクラス属性として呼び出すことができます。以下の実装では`LoginPage.login`メソッドで、これらの属性を使用してログイン処理を行っています。

```python:login_page.py
from selenium.webdriver.common.by import By
from .base import Model
class LoginPage(Model):
    USERNAME = (By.ID, "username")
    PASSWORD = (By.ID, "password")
    LOGIN_BUTTON = (By.ID, "login-button")

    def login(self, username: str, password: str) -> None:
        self.username.send_keys(username)
        self.password.send_keys(password)
        self.login_button.click()
```

## おわりに

Seleniumには[Implicit waits](https://www.selenium.dev/documentation/webdriver/waits/#implicit-waits)もありますが、これは要素の出現以外も含めたすべての待機に適用されるため、意図しない待機が発生してしまう可能性があると思います。ここでの実装のように明示的に待機を指定することで、必要な待機のみを行うことができます。

<!-- zenn article id: f660bc06b71bda -->
無料でそこそこ?使える金銭的に厳しい人向けの生成AI・コーディングエージェント

# 概要

金銭的に余裕がなくそれでも生成AIやコーディングエージェントを使いたい人向けに
**無料がサイコーというわけではなく、ちゃんとお金を払った方が良いとはお思います。そこは注意。**

## 結論

Gemini強いなぁ


## 一覧

### WebUI型

| 名称 | 開発元 | 備考 |
| :--- | :---: | --- |
| Gemini | Google | https://gemini.google.com/app <br>から無料で使える。<br>2.5 Flashがデフォルトで使えるため、そこそこ調べ物で有効そう。|
| Copilot | Microsoft | https://copilot.microsoft.com/ <br>から無料で使える。<br>Microsoftアカウント登録することでThink Deeperモードも無料で使える。|


### API

| 名称 | 開発元 | 備考 |
| :--- | :---: | --- |
| Gemini | Google | https://aistudio.google.com/ <br>からAPIキーを登録し無料で使える。<br>無料プランではレート制限が厳しい・API経由でも学習に使用されるなど注意が必要。|

### エディタ型

| 名称 | 開発元 | 備考 |
| :--- | :---: | --- |
| Cursor | Anysphere Inc. | https://www.cursor.com/ <br>からDLして無料で使える。<br>無料プランでも上記のGeminiのAPIと組み合わせることで、そこそこ試すことはできる。|
| Windsurf | Windsurf | https://windsurf.com/download <br>からDLして無料で使える。<br>無料プランでもタブでの自動補完機能がそこそこ使える。目玉となるCascade機能は有償プランにならないとあまり使えないかも。|


### CLI型

| 名称 | 開発元 | 備考 |
| :--- | :---: | --- |
| Warp | Warp | https://www.warp.dev/ <br> Windows・Mac・Linuxいずれも対応している。<br>無料プランでもコマンドの補完記法などがそこそこ使える。エージェントモードでのコーディングも可能。<br>日本語入力がかなり不便などの欠点はある。 |

### 自律型

| 名称 | 開発元 | 備考 |
| :--- | :---: | --- |
| OpenHands | OSS | https://docs.all-hands.dev/ <br> クラウド型もあるがDockerをなどを使ったセルフホスト型で無料で利用できる。<br> APIが必須だが上記のGeminiと組み合わせることで、無料で自律型コーディングを試せる。|


### その他

| 名称 | 開発元 | 備考 |
| :--- | :---: | --- |
| Gemini Code Assist | Google | https://github.com/apps/gemini-code-assist <br> からGitHubのアプリとして連携させるとことでPRの自動レビューなどが可能。<br>Gemini 2.0が基盤だからかレビューの回答が若干あやふやな感じもする。<br> VSCodeプラグインとしても使うことも可能。|

### 所管

Gemini依存激しい・・・
やはり課金した方が（ry


## 参照

https://ai.google.dev/
https://www.cursor.com/
https://windsurf.com/
https://www.warp.dev/
https://docs.all-hands.dev/
https://cloud.google.com/blog/ja/topics/developers-practitioners/gemini-code-assist
PostgreSQLでドメイン型を利用する(tsrangeを拡張する)

## はじめに
表題通り、PostgreSQLが持つ基本の型を拡張するドメイン型を作成します。
今回は、tsrangeを拡張します。

## ドメイン型 (Domain Type)って何？？

- **概要**  
  - 既存の型（例: `integer`, `tsrange`）に対して制約を追加した「ラッパー型」

- **メリット**  
  1. **再利用性**：同じ制約を何度も書かずに済む  
  2. **一貫性**：制約を変更すると、ドメインを使っているすべての列に自動適用  
  3. **可読性**：型名から用途や制約内容が直感的にわかる

- **定義例**  
```sql
 CREATE DOMAIN positive_int AS integer
    CHECK (VALUE > 0);
```


## 実践
今回は`tsrange`を拡張します

```sql:
-- tsrange のラッパー型を定義
CREATE DOMAIN tsrange_wrap AS tsrange
  CHECK (
    -- 無限端点でないこと
    NOT lower_inf(VALUE)
    AND NOT upper_inf(VALUE)
    -- 空範囲でないこと
    AND NOT isempty(VALUE)
    -- 左端は inclusive ([)
    AND lower_inc(VALUE)
    -- 右端は exclusive ())
    AND NOT upper_inc(VALUE)
  );

-- テーブル定義で直接使用
CREATE TABLE calendar_events (
  id         serial         PRIMARY KEY,
  title      text           NOT NULL,
  time_range tsrange_wrap NOT NULL
);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/e07c46bb-a291-467c-b3c7-f97bf754210c.png)

→型がちゃんとtsrange_wrapになっていることを確認できます。

### 実行結果
では実際に実行していきます！

```sql
-- 成功例（すべてのドメイン制約を満たす: finite・非空・左端 [・右端 )）
INSERT INTO calendar_events (title, time_range)
VALUES (
  'Valid Event',
  '[2025-06-01 09:00,2025-06-01 11:00)'::tsrange_wrap
);

------------------------------------------------------------
-- 失敗例1：左端が開区間 ‘(’ のため lower_inc(VALUE) が FALSE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
  'NG 左開放',
  '(2025-06-01 09:00,2025-06-01 11:00)'::tsrange_wrap
);
-- ERROR:  value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"

------------------------------------------------------------
-- 失敗例2：右端が閉区間 ‘]’ のため NOT upper_inc(VALUE) が FALSE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
  'NG 右閉鎖',
  '[2025-06-01 09:00,2025-06-01 11:00]'::tsrange_wrap
);
-- ERROR:  value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"

------------------------------------------------------------
-- 失敗例3：上限が無限大 ‘)’ のため upper_inf(VALUE) が TRUE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
  'NG 無限端点',
  '[2025-06-01 09:00,)'::tsrange_wrap
);
-- ERROR:  value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"

------------------------------------------------------------
-- 失敗例4：空レンジ ‘empty’ のため isempty(VALUE) が TRUE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
  'NG 空レンジ',
  'empty'::tsrange_wrap
);
-- ERROR:  value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"
```
Huskyでコミット直前に「対象ファイルだけformat」とtestを実行したい

## この記事で実現すること

チームでのアプリケーション開発で、次のようなことがあると思う。

- 「未フォーマットのファイルをコミットしてしまった」
- 「テストが通っていないのにコミットしてしまった」

こういったことがあると、余計な仕事が増えて辛い。今回の記事で実現するのは、これらを事前に回避してプロジェクトの品質を下げない＆余計な仕事減らすこと。

今回はJavaScript, TypeScriptでのプロジェクト使える **「Husky」** というツールを使ってこれを実現する。

## Huskyってなに？

https://typicode.github.io/husky/

git commit や git push の前に任意のコマンド・スクリプトを挿入できるツールだよ。

自分はよく、TypeScriptのプロジェクトでコミットする時に、

1. Prettierでステージング済みのファイルだけフォーマット
1. フォーマットしたファイルを git add
1. 最後にテストを実行して、テストが通れば git commit実行

という流れをHuskyで構築してる。よく使うのだけど毎回どうしてたか忘れてるので、記事として今回まとめることにした。

## 事前準備

※前提: 下記ではパッケージマネージャにはBunを使っています。npmなど他のパッケージマネージャを使っている場合には適宜読み替えてください（例:  `bun i -D` == `npm i -D` , `bunx` == `npx` , `bun run` == `npm run` ）

```sh
bun i -D husky
bunx husky init
```

これでHuskyを使う準備は完了。
なおこの記事を書いている時点でのHuskyのバージョンは `9.1.7` 。

## 本題: pre-commit時に「Prettierでステージング済みファイルのフォーマット」と「テストの実行」をするスクリプトを実装

ここで実装するスクリプトによって実現するフローは次のとおり。

- git commit を実行すると、コミット直前にPrettierでステージング対象のファイルにフォーマットを行う
- フォーマットが終わったらテストを実行
- テストが通ればコミットが行われる

早速書いていく。こう。

package.jsonに次のようなscriptが用意されてるとして...

```json:package.json
  "scripts": {
    "test": "bun test",
    "prettier": "prettier",
    "prepare": "husky"
  }
```

```sh:.husky/pre-commit
#!/bin/sh

# ステージに追加されたファイルのみをフォーマット
FILES=$(git diff --cached --name-only --diff-filter=ACM)
if [ -n "$FILES" ]; then
  echo "Formatting staged files..."
  # フォーマット対象外のファイルでエラーになったとしても無視
  bun prettier --write $FILES || true
  git add $FILES
fi

# テスト実行
echo "Running tests..."
bun run test
```

これで実装完了！

## 使い方

本当にただ git commit するだけ！

```sh
git add コミットしたいファイル
git commit -m "任意のコミットメッセージ"
```

これでステージング済みのファイル（つまり git add したファイル）だけが Prettierでフォーマットされて、テストが通ればコミットが実行される。

もちろんテストが通らなかった場合は、コミットが行われずに処理が終わるので、

- 「未フォーマットのファイルをコミットしてしまった」
- 「テストが通っていないのにコミットしてしまった」

といった事態を防いでプロジェクトの品質を維持できる。
コラボ回ということで参加してきたJAWS

- ご挨拶

こんにちは。JAWS-UGクラウド女子会運営の白"雪姫"です。
今回は，そちらのコラボ回ということで，実況も兼ねて行ってきました！

- JAWS-UGとは？

JAWS-UGとは、AWS (Amazon Web Services) が提供するクラウドコンピューティングを利用する人々の集まり（コミュニティ）です。
一人ではできない学びや交流を目的としてボランティアによる勉強会の開催や交流イベントなどを行なっています。
私たちは日本全国に「支部」の形でグループを持ち、それぞれのテーマに基づいて活動を行なっています。
このコミュニティーは、非営利目的で活動しています。

[公式サイト](https://jaws-ug.jp/about-us/)より

- 今回は支部コラボ

今回は，[情シス支部主催・クラウド女子・札幌支部のコラボ企画](https://jawsug-sysad.connpass.com/event/350914/)ということになりました。

- 発表内容のお話

今回は，LTとチョークテーマという2本立てです！！
印象に残った物を2本ほど紹介します！

- AWS Card clashの話

[makiさん](https://x.com/makies)のCard clash
なんとこちら，ゲームをしながらAWSのベストプラクティス構成を学べてしまうというゲーム！
アプリもあるらしく，iPadなどでもできるという優れもの。
調べてみたら，基礎知識も学べてしまうそうです。
みんなで是非やってみませんか？

詳しくは[こちら](https://aws.amazon.com/jp/training/digital/aws-card-clash/)です。


- AWS-UGへの関わりの変遷と得たもの

[五味なぎさ](https://x.com/nagisa_53)さんのトーク。
個人的に感想を書くならば「つよつよエンジニアも最初の一歩はつよつよじゃない」ですね。
JAWSに五味さんが関わった事による自身の編纂と得た物を紹介してくれました。

- 全体的に

みんな楽しく，明るくそして技術力の吸収ができる会となっていたかなと思っています。
強いて言うなら，チョークトークの時間はもう少し取っても良いかも？とかとかちょっと思ったりしました。

- 最後に

私も，「この人，その実，つよつよな方です」と最近は紹介してくれたりしてますが，私自身は最初はそんなこと無いと思っています。
交流していく上で「こんな事出来るのでは？」とか「こういうことやった方が良いかもね」とかの情報からまたやってみるというトライアンドエラーを繰り返しています。
そんな情熱，持ってみませんか？
私が読書会に参加する際に意識していること

# 前置き

以下のような場合はそっちに時間を割いたほうがやりたいことに対して最短だとは思います。

* 自分が明確に作りたいものを持ってるとき
  * コードを書いてしまう
* 最先端の流行を追いたいとき
  * 言語仕様、RFC、リリースノート、論文を読む

が、それでも読書会に参加すること自体悪くないと思っているので、自分の思考の整理がてら書いてみます。

# 私が参加している読書会について

私が参加してる読書会は書籍を一字一句音読して、気になることがあれば議論するという形式のものです。時間があればしてもいいのですが、大抵ないので事前準備はしません。

直近参加した読書会は[第4回『Go言語で学ぶ並行プログラミング』オンライン読書会](https://technical-book-reading-2.connpass.com/event/350009/)です

# 音読して気づくこと
音読してみて気づくのは、人間は文章そのものを読んでいるというよりは脳が処理した結果を読んでいるので、他の人がありもしない単語を読んでるということです。自分自身にも当てはまります。

# 読書会に参加する際に意識していること

自分が読んでるとき他の人が読んでるときはそれを聞きながら自分が論理を追えてるかを意識して聞いてます。分からなかったとき、何が分からないか分からないときはその旨をメモし、それを後で調べます。

可能なら、読書会中に、ソースコードがある場合はgit cloneして、プログラムを実行したり、コード全体を眺めたり、linuxコマンドならmanコマンドで調べてみたり、Goのライブラリならgo docで調べてみたり、chatGPTやPerplexityで調べたりしながら読んでます。

読書会が終わった後は可能なら些細な内容でもいいのでブログを書くようにしてます(書けないときもあります)。アウトプットすると理解が深まるからです。

# 丁寧に理解して整理すること

上記の内容は音読形式の読書会でなく、それ以外の輪講形式の勉強会でも、LTでも、その他何らかのイベントでも当てはまると思います。一人だとなかなか学習が続かないのに対して、読書会があると一定の拘束力が働くし、他の人と議論したり話を聞く機会が増えるので、多くの知識やノウハウを得ることができます。必ずしも最先端の知識やノウハウでなくとも、丁寧に内容を理解して整理する時間は有用ではないでしょうか。

という、真新しい内容のない、ポエムでした。
【冨井悠平】駆け出しエンジニアが「壁」にぶつかった時、試してほしい5つの思考法

前回の記事では、これからエンジニアとしてのキャリアをスタートさせる皆さんに、最初に意識すべき大切なことをお伝えしました。今回は、少し視点を変えて、エンジニアとしてキャリアを歩む中で必ず訪れる「壁」にぶつかった時、どう考え、どう乗り越えていけば良いのかについて、私自身の経験も踏まえながらお話ししたいと思います。

１．「なぜ？」を深掘りする探求心を持つ
エラーメッセージとにらめっこしたり、原因不明のバグに時間を費やしたり…。エンジニアのキャリアには、必ずと言っていいほど「わからないこと」の壁が立ちはだかります。そんな時、ただ表面的な解決策を探すのではなく、「なぜこうなるのか？」「根本的な原因は何なのか？」という探求心を持つことが大切です。

例えば、API連携でエラーが出た時。「エラーコード〇〇で通信に失敗しました」という情報だけで終わらせず、「なぜこのエラーコードが出ているのか？」「リクエストの形式は正しいか？」「サーバー側の処理に問題はないか？」と、芋づる式に疑問を掘り下げていくのです。この深掘りこそが、真の理解に繋がり、同じ壁に再びぶつかることを防ぐ力になります。

２．「完璧主義」を手放してみる勇気
特に真面目な人ほど陥りやすいのが、「完璧なコードを書かなければ」というプレッシャーです。もちろん、品質の高いコードは重要ですが、最初から完璧を目指しすぎると、なかなか前に進めなかったり、些細なことで立ち止まってしまったりすることがあります。

大切なのは、**「まずは動くものを作る」**という意識を持つこと。プロトタイプやPoCの段階では、多少粗削りでも、まずは形にすることが重要です。その後、フィードバックを得ながら改善していくというアプローチの方が、結果的に早く、より良いものを作り上げることができます。「完璧」は後から追い求めるものでも良いのです。

３．「誰かに頼る」ことを恐れない
エンジニアは個人プレーのイメージがあるかもしれませんが、実際はチームで協力して開発を進めることがほとんどです。どうしても解決できない問題に長時間行き詰まるよりも、積極的に周りの先輩エンジニアや同僚に助けを求めることも、重要なスキルの一つです。

「こんな簡単なことを聞いても良いのかな…」と躊躇してしまう気持ちも分かります。しかし、多くの場合、経験豊富なエンジニアは快く手を差し伸べてくれます。質問することで、自分だけでは思いつかなかった解決策が見つかったり、新たな知識や視点を得られたりすることも少なくありません。

４．「小さな成功体験」を積み重ねる
大きな壁に直面すると、自分の能力を疑問に思うこともあるかもしれません。そんな時は、無理に大きな課題に立ち向かうのではなく、少し手を伸ばせば解決できるような小さな課題に取り組んでみましょう。

例えば、「簡単なバグを一つ修正する」「短い関数を一つ実装する」「ドキュメントを少し整理する」など、どんな小さなことでも構いません。それを一つ一つクリアしていくことで、「自分にもできる」という自信を取り戻し、再び大きな壁に立ち向かうエネルギーをチャージすることができます。

５．「視点を変える」ことで見えてくる光明
どうしても解決策が見つからない時や、同じ考えに囚われてしまった時は、意識的に視点を変えてみることが有効です。

例えば、「もし自分がエンドユーザーだったら、この問題をどう感じるだろうか？」「もし別の技術を使っていたら、どう解決できるだろうか？」「全く違う分野の知識を応用できないだろうか？」など、普段とは違う角度から問題を捉え直すことで、予期せぬ解決策が見つかることがあります。時には、物理的に場所を変えてみるだけでも、気分転換になり、新たなアイデアが浮かんでくることもあります。

エンジニアの道は、決して平坦ではありません。しかし、壁にぶつかるたびに、そこで立ち止まってしまうのか、それとも新たな思考法を身につけて乗り越えていくのかで、その後の成長は大きく変わってきます。

今回お伝えした5つの思考法は、私がこれまでのキャリアの中で、多くの壁にぶつかり、そして乗り越えてきた経験から得たものです。もし今、壁に苦しんでいる駆け出しエンジニアの方がいたら、ぜひこれらの考え方を試してみてください。きっと、新たな光明が見えてくるはずです。そして、もし何か困ったことがあれば、いつでもお気軽にご連絡ください。一緒に、その壁を乗り越える方法を探しましょう。
猿でもわかるAIプログラミングシリーズ 🐵💻 AIを作るための数学（中学生レベルでOK）



---

## 1. はじめに：AIって結局、数学なの？

「AIって難しそう…数学とか苦手だし無理かも」
そんな声を現場の若手エンジニアからよく耳にします。でも実は、AIを作るうえで使う“本質的な数学”は、**中学数学レベルでも十分理解可能**です。

本記事では、**機械学習アルゴリズムの土台となる基本的な数式や概念**を、具体的なコード例とともに解説します。とにかく“実際に動かして納得する”ことを重視し、現場での応用にもつながるヒントを盛り込みました。

「理論よりコードで理解したい」「手を動かしながら数式を読み解きたい」そんなエンジニアの方にぴったりの記事です。

---

## 2. 数学の基礎：AIが使う中学生レベルの知識とは？

### 2.1 ベクトルとスカラーの違い

| 用語   | 意味               | 例           |
| ---- | ---------------- | ----------- |
| スカラー | 単一の数値            | 3, -1.5, π  |
| ベクトル | 数の集まり（向きと大きさを持つ） | `[1, 2, 3]` |

AIにおけるデータや特徴量は、ほぼすべてベクトルとして扱われます。

### 2.2 内積（ドット積）とは？

2つのベクトルの類似度を表す基本的な演算です。
AIでは「入力×重み」の演算として頻出します。

$$
\text{内積} = x_1 w_1 + x_2 w_2 + \cdots + x_n w_n
$$

Pythonで書くと：

```python
import numpy as np

x = np.array([1.0, 2.0])
w = np.array([0.3, 0.7])
dot = np.dot(x, w)
print(dot)  # 出力: 1.7
```

---

## 3. 【実例】内積だけでAIっぽい処理をしてみよう

### 3.1 問題設定：スパムメール判定をしてみよう

以下のような特徴量（仮の数値）を使って、メールがスパムかどうかを判断するシンプルな「AIっぽい関数」を作ります。

| 特徴量              | 値の意味                       |
| ---------------- | -------------------------- |
| `contains_free`  | 「free」が含まれる → 1、含まれない → 0  |
| `contains_click` | 「click」が含まれる → 1、含まれない → 0 |

```python
def simple_spam_checker(x, w, threshold=0.5):
    score = np.dot(x, w)
    return "SPAM" if score >= threshold else "NOT SPAM"

# 例：freeあり、clickあり
x = np.array([1, 1])
w = np.array([0.6, 0.7])
print(simple_spam_checker(x, w))  # SPAM

# 例：freeなし、clickあり
x = np.array([0, 1])
print(simple_spam_checker(x, w))  # NOT SPAM
```

### 3.2 この関数がやっていること

* `x`は入力特徴ベクトル
* `w`は重み（重要度）
* 内積でスコアを計算 → 閾値で判定

つまり、「重み付きの特徴量合計」が**しきい値を超えるかどうか**を見ているだけです。これが、**AIモデルの本質的な動作の一つ**です。

---

## 4. 現場Tips：AIっぽい処理を理解するコツとハマりがちな落とし穴

### ✅ コツ

* **特徴量設計が9割**：どの情報をどのようにベクトル化するかが重要
* **重みの直感を大事にする**：「この特徴に重み0.7って、高すぎない？」など、チューニング感覚を養う

### ❌ よくある失敗

* **スケーリングの違いを無視**：特徴量のスケールがバラバラだと重みの意味が壊れる
* **閾値の設定が雑**：業務要件に応じて精度/再現率などのバランスを調整すべき

---

## 5. 応用編：重回帰分析やニューラルネットとのつながり

この“内積+しきい値”の考え方は、以下の技術の土台にもなっています：

* **線形回帰**：内積の結果をそのまま数値として使う（価格予測など）
* **ロジスティック回帰**：内積をシグモイド関数で0〜1に変換
* **ニューラルネット**：内積 + 活性化関数 の繰り返し

たとえば、ニューラルネットで使われる最も基本的な式は以下の通りです：

$$
y = \sigma(\sum x_i w_i + b)
$$

この式の中核は、まさに内積です！

---

## 6. まとめ：数学は“理解の武器”

### ✅ 本記事のまとめ

* AIで使われる数学は、**中学レベルの足し算・掛け算・内積**が中心
* コードで動かしながら学ぶと数式も怖くない
* 数式の意味を理解することが**AIモデルのチューニングや精度改善**に直結する

### 🔮 今後の展望

このようなシンプルな「AIっぽい処理」を理解することで、より高度なライブラリ（PyTorchやscikit-learn）の**中身**がわかるようになり、現場での応用力も高まります。


---

🧠「AIは魔法じゃない」と実感できた方は、ぜひ試してみてください！質問やコメントも歓迎です。

---

## 💡補足資料（読み物）

* [Pythonで学ぶベクトルと内積の基本](https://...)
* [NumPyの基礎：配列計算の力を活かす](https://...)
猿でもわかるAIプログラミングシリーズ 🐵💻 NumPyの基本操作だけでできるAIっぽい処理



## NumPyだけで作る「AIっぽい処理」入門

---

## 1. はじめに：AIって本当に難しいの？

「AI開発」と聞くと、多くの人が以下のようなイメージを持つのではないでしょうか？

* 難解な理論や数学が必要
* TensorFlowやPyTorchのような重厚なライブラリを使う必要がある
* GPUを用意しないとダメそう…

実は、**NumPyの基本操作だけでも「AIっぽい」処理は再現できる**のです。本記事では、現役エンジニアの視点から、AIの本質的な考え方をNumPyを使って体験できる内容を紹介します。

---

## 2. NumPyでできるAIっぽい処理とは？

ここでいう「AIっぽい処理」とは、以下のようなロジックを指します：

* データからパターンを抽出する（線形回帰）
* 自動的に分類する（k-meansクラスタリング）
* 重みを用いた予測（単純なパーセプトロン）

これらは、NumPyの `配列`, `行列演算`, `ブロードキャスト`, `条件フィルタ` を使えば、意外とシンプルに実装できます。

---

## 3. 実装してみよう！NumPyで線形回帰

### 3.1 問題設定

まずは、以下のような身近なデータから、「気温（X）」から「アイスの売上（Y）」を予測するシンプルな線形回帰モデルを実装します。

```python
import numpy as np
import matplotlib.pyplot as plt

# ダミーデータ
X = np.array([20, 22, 24, 26, 28, 30])
Y = np.array([100, 120, 140, 160, 180, 200])
```

### 3.2 回帰直線のパラメータをNumPyだけで求める

```python
# 平均を計算
x_mean = np.mean(X)
y_mean = np.mean(Y)

# 回帰係数（傾き）
numerator = np.sum((X - x_mean) * (Y - y_mean))
denominator = np.sum((X - x_mean) ** 2)
slope = numerator / denominator

# 切片
intercept = y_mean - slope * x_mean

print(f"回帰式: y = {slope:.2f}x + {intercept:.2f}")
```

### 3.3 可視化してみる

```python
plt.scatter(X, Y, label="観測データ")
plt.plot(X, slope * X + intercept, color='red', label="回帰直線")
plt.xlabel("気温 (℃)")
plt.ylabel("売上 (個)")
plt.legend()
plt.title("NumPyで線形回帰")
plt.grid()
plt.show()
```

---

## 4. 実務で使えるちょっとしたテク＆ハマりポイント

### ✅ 実務に役立つTips

* `np.dot()` を使えば明示的な行列積も可能
* ベクトル化された演算で `for` ループを排除し、処理速度向上
* ダミーデータは `np.random.randn()` と `np.linspace()` を組み合わせて自作可能

### ⚠️ よくある落とし穴

| 問題            | 原因          | 対処法                                                          |
| ------------- | ----------- | ------------------------------------------------------------ |
| 計算結果がnanになる   | 0除算、無限大の扱い  | `np.seterr(divide='ignore', invalid='ignore')` を使って無視またはデバッグ |
| `shape` ミスマッチ | ブロードキャストの誤解 | `.reshape(-1, 1)` で明示的に次元を合わせる                               |

---

## 5. さらに進む人向け：パーセプトロンもNumPyで書いてみよう！

以下は、NumPyだけで書いた単純なパーセプトロンの例です。

```python
# データセット（ANDゲート）
X = np.array([[0,0], [0,1], [1,0], [1,1]])
Y = np.array([0, 0, 0, 1])

# 重みとバイアス
W = np.random.randn(2)
b = np.random.randn()

# 活性化関数（ステップ関数）
def step(x):
    return np.where(x > 0, 1, 0)

# 学習率とエポック
lr = 0.1
epochs = 10

for epoch in range(epochs):
    for x, y in zip(X, Y):
        z = np.dot(W, x) + b
        pred = step(z)
        error = y - pred
        W += lr * error * x
        b += lr * error
```

---

## 6. まとめ：NumPyだけでも「AIの感触」は味わえる

### ✅ NumPyの力を再認識しよう

* 数学的な処理や機械学習の「原型」を知るにはNumPyが最適
* 本質を理解すれば、フレームワークに頼らずロジックから理解できる

### ❌ 限界も理解しよう

* モデルの複雑性・性能チューニングは限界あり
* 実プロジェクトではやはりscikit-learnやPyTorch等の導入が必要

---

## 参考リンク

* NumPy公式ドキュメント：[https://numpy.org/doc/](https://numpy.org/doc/)
* AIの基礎理論：Pattern Recognition and Machine Learning（Bishop）

---

ご質問・フィードバックなどありましたら、コメントでぜひお知らせください！
prisma db seedでseedが実行できない


## 概要
prismaで`npx prisma db seed`を実行した際に意図した結果にならなかったので解決していきます。
Next.js15系 x prisma 6系です。

## 前提
package.jsonの一部
```
"@prisma/client": "^6.8.2",
"next": "15.3.2",
"prisma": "^6.8.2",
"ts-node": "^10.9.2"
```

package.jsonのscripts
```
"scripts": {
"prisma": {
		"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
	}
}
```

ファイル構造
```shell
prisma/
	schema.prisma
	seed.ts # seed
src/
```

`npx prisma migrate dev`でtable作成済み
## 何が起きた
seedを実行するためにprisma/seed.tsに処理を記述し、`npx prsima db seed`を実行しましたが `Environment variables loaded from .env`と表示されるだけでseedが実行されませんでした。

## 試したこと
prisma GitHubのissueを確認すると、.evnのDATABASE_URLに起因するエラーが散見されるので、CUSTAM_DATABASE_URLに命名を変更して実行してみました。  
結果: 変化せず


npx prisma db seed使わずに直接実行`npm run prisma:seed`してみました

---

```
"scripts": {
	"prisma:seed": "ts-node --compiler-options '{\"module\":\"CommonJS\"}' prisma/seed.ts"
}
```
結果: seedが実行されました

---
echo sampleに書き換えてみました。
```
"prisma": {
  "seed": "echo sample"
}
```

結果: 変わりませんでした。 scripts.prisma.seed自体が動いてない?

---
scriptsの外に出してみる
```json
"prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  },
```

結果: seedが実行されました


## 原因
実は正しく動作しない理由はscriptsの中に記述しているからでした。


## 解決策
以下指定はscriptsの外である必要がります。
```json
"prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  }
Gitでコミットを一つにまとめたい

## 概要
複数コミットを一つのコミットにまとめたい

## 手順

### 1. 作業中の変更をコミットまたはスタッシュする
現在作業中の変更があれば、コミットするかスタッシュ（退避）してください。
未保存の変更があるとリベースを始められません。

``` 
   git add .
   git commit -m "WIP" # 必要に応じてコミットメッセージを付ける
```

または、変更をスタッシュする場合

``` 
   git stash
```


### 2. リベースを開始
まとめるコミットの数を確認した上で、`git rebase -i HEAD~<コミット数>` を実行します。
例えば、過去5つのコミットをまとめたい場合

``` 
   git rebase -i HEAD~5
```


### 3. インタラクティブリベースの設定
コマンドを実行すると、デフォルトのエディタ（例: Vim）が開き、以下のような画面が表示されます

``` 
   pick 123abc Initial commit
   pick 456def Added email validation
   pick 789ghi Fixed resend bug
   pick abc123 Refactored validation code
   pick def456 Final tweaks
```

ここで、最初のコミット (例: `123abc`) はそのまま `pick` のままにします。他のコミットに対しては `squash`（または省略して `s`）に変更してください。
例：

``` 
   pick 123abc Initial commit
   squash 456def Added email validation
   squash 789ghi Fixed resend bug
   squash abc123 Refactored validation code
   squash def456 Final tweaks
```
`squash` の意味：対象のコミットを直前のコミットに統合します。


### 4. コミットメッセージを編集する
次に、統合後のコミットメッセージの編集画面が開きます。ここで、まとまったコミットの説明を1つに記述し、不要なメッセージは削除できます。
例：
``` 
   # This is a combination of 5 commits.
   # The first commit's message is:
   Initial commit

   # The following commit messages will also be included:
   Added email validation
   Fixed resend bug
   Refactored validation code
   Final tweaks
```
必要に応じて、以下のように1つのメッセージに整理します：
``` 
   Added email validation and fixed related issues.
```
保存してエディタを閉じます。


### 5. リベースの完了
リベースが正常に完了すると、Gitは自動的に統合されたコミットを更新します。


### 6. 作業内容を確認
まとめられた状態を確認するには、以下のコマンドを使用します

``` 
   git log
```

まとめられた1つのコミットが表示されるはずです。


### 7. リモートブランチへの反映
リモートブランチに変更を反映する場合は、`--force`（または短縮形の `-f`）オプションを利用してプッシュします。
注意：この操作は強制プッシュなので、リモートの履歴が上書きされます。

``` 
   git push --force
```


##
プロダクトに向き合い、ユーザーとつながる開発を。
ネットネイティブでは、そんなエンジニアを歓迎しています
https://www.wantedly.com/companies/mdpr
【SAPUI5】ControllerでODataメタデータからEntityのプロパティ情報を取得する方法

SAPUI5で開発していると、「ODataモデルのメタデータから特定のEntityのプロパティを取得したい」という場面があります。たとえば、動的にテーブルカラムを生成したい場合などです。

この記事では、Controller内でEntityのプロパティ情報を取得する方法を紹介します。

✅ 使用する前提
モデルはODataModel（v2）

メタデータは事前に読み込み済み（metadata.xmlにEntity定義が存在する）

モデル名はoModelとして例示

🧩 コード全文
以下が、Controller内でEntityのプロパティ情報を非同期で取得するコードです。

// メタデータから Entity のプロパティ情報を抽出
let oMetadataArr = await new Promise(
    function (fResolve, fReject) {
        oModel.getMetaModel().loaded().then(() => {
            let oMetaModel = oModel.getMetaModel().getODataEntityType("Namespace.EntityName");
            fResolve(oMetaModel?.property ?? []);
        }).catch(fReject);
    }
);

🔍 解説
oModel.getMetaModel()
ODataModelからメタモデル（MetaModel）を取得します。

ここにはEntityTypeやPropertyなどの情報が含まれています。

loaded().then(...)
メタデータの読み込みは非同期のため、loaded()で読み込み完了を待つ必要があります。

この中で安全にメタデータアクセスを行います。

getODataEntityType("Namespace.EntityName")
引数には 完全修飾名（Namespace付き） のEntity名が必要です。

例："my.service.namespace.DestinationSet"

SAP GUIのODataメタデータ（metadata.xml）で確認できます。

?.property ?? []
取得できなかった場合に備え、nullチェック＋空配列のデフォルトを指定しています。

🧪 使用例：プロパティ名だけ取得したい場合
js
let aPropNames = oMetadataArr.map(o => o.name);
// 例: ["ID", "Name", "Address", "Email"]
⚠️ 注意点
getODataEntityType() に渡す エンティティ名は正確に。

EntitySet名（例: "Destinations"）ではなく、EntityType名（例: "ZC_DestinationsType"）を指定します。

メタデータがまだ読み込まれていない段階でアクセスしようとすると、undefinedが返る可能性があります。

📝 おまけ：非async/await版（Promiseチェーン）
oModel.getMetaModel().loaded().then(() => {
    let oMetaModel = oModel.getMetaModel().getODataEntityType("Namespace.EntityName");
    let aProps = oMetaModel?.property ?? [];
    console.log(aProps);
});
🙌 まとめ
SAPUI5では、MetaModelを使えば動的にEntityの情報を取得できます。
特にテーブルカラムの動的生成や、入力チェックの自動化など、柔軟なUI設計に役立ちます。