OmniAICreator/Qiita-1.07M huggingface dataset:
Entra IDとExchange Onlineの裏仕様を勝手に信用して裏切られた話

# まとめ
公式ドキュメントに記載されていない仕様を見つけても、むやみに利用するのはやめよう！

# あらまし
組織内部の希望者に向けて、Webフォームで申請するとEntra IDにアカウントを作成、Exchage Onlineのアカウントを振り出してメールが利用できるようになるサービスを提供している。

# Global Address Book(GAL)の問題
ただし、サービスの利用者はお互いに（直接の）面識があるとは限らないため、Exchange Onlineのデフォルト設定であるアドレス帳へのメールアドレスの表示は無効としておきたい。そのため、「グローバルアドレス一覧から非表示」の設定を行いたいのだが、Exchange管理センターから手作業で設定変更を行うようなことはせず、また、PowerShellコマンドで設定変更[^1]を行うのも面倒（自動化を含め）だと思ったので、他の方法を考えることにした。

なお、オンプレADは存在しないため、Entra ID Connectでの連携などは行っていない。

# Global Address Bookへの対応方法
いろいろ調べていると、Microsoft Graphを利用して操作するUserオブジェクト[^2]に **showInAddressList** というプロパティがあり、現在の設定を確認することができると分かった。

実際には HiddenFromAddressListsEnabled というフラグをExchange Online側で持っていて、showInAddressList はEntra IDで表示時に算出しているだけとか言われてる[^3]。

ただし、当時の記憶では **この値を直接操作するな** と記載があった。**それならユーザ作成時に値をtrueにして与えたらいいんじゃね？変更じゃないし** などと考えて試してしてみると、期待通りに動作してくれた。数十回のテストを行った後、この仕様で行くことにした。

:::note info
邪道だと指摘されそうだが、ユーザ作成時にGALから非表示にする方法が用意されていないため、正攻法でもユーザ作成後にPowerShellでGALから非表示またはAddress Book Policyを各ユーザに設定する必要がある。
:::

本番運用開始後もしばらくは様子を確認していたが問題はなかった、あの時までは…

# 問題発覚
たまたはOutlookでアドレス帳を見たときになぜか空になっているはずの場所にいくつかのメールアドレスが表示されていることを確認。狭い範囲の日時でしか発生しておらず、ログ等を調査してもエラーなどは確認できないため、**Exchange Online側の仕様が突然変更され、数日後元に戻った** としか思えない状況だった。

まぁ非推奨の手段が原因で発生した問題なので、MSに問い合わせたとしてもまともな回答がもらえるとは思えなかったため、そっと手動でGALから非表示に設定をしたのち、対象アドレスにお詫びメールを送付して終了。

# 再発防止策
定期的にGALに表示されているメールアドレスが無いか確認し、存在していれば非表示に設定変更するPowerShellスクリプトを作成して終了。

[^1]: https://learn.microsoft.com/ja-jp/exchange/address-books/address-lists/manage-address-lists

[^2]: https://learn.microsoft.com/ja-jp/graph/api/resources/user?view=graph-rest-1.0

[^3]: https://stackoverflow.com/questions/54316503/microsoft-graph-how-to-switch-off-show-in-global-address-list-for-new-user#comment121311426_54319230
AtCoder ABC385 C　自分なりに詳しく解説(python)

# はじめに
https://atcoder.jp/contests/abc385/tasks/abc385_c

１時間以上かけて解きましたが、貰えたのはWAとTLEと絶望でした。

悔しいので、公式解説の**k+1・・・の実装**の為の解説をします。

稚拙ながら、公式解説に補足する形で話していくので、
まずは、解説の方をご覧になってから読んで頂ればと思います。
# 探索の目星をつけよう
まず、今からやることを図で示します。
下の数字は、correctの値です。
### K=1
![k1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3740708/dd976a2c-e422-6bfe-54b0-1ef5e49552b9.png)
### K=2
![k2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3740708/2c8daf92-808b-fccd-e181-39b93a6e0fb8.png)
### K=3
![k3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3740708/17e47f00-dc15-a3a1-1803-9b0c5ef5d6fa.png)


と、上図の通りになります。（Kはさらに続きます。）
見て考えると、このコードは、
**①Ｋ飛ばし分スタート位置を一つずらし、その度実行する(k=1なら(0)、k=2なら(0,1))。**
**②Ｋずつ飛ばして、解説の問題Ｘのコードと同じように実装する。**

①をやる理由は、一度しかやらないと図の赤い部分しかやらないことになる為です。
また、図を見ていると、Ｋ飛ばし分だけスタート位置を変え、実行すると全ての数字が読めることも分かると思います。
# コード例
では、①、②の通りに実装してみましょう。
```python:コード例
n = int(input())
h = list(map(int,input().split()))
ans = 1
#飛ばす距離をｎまでやる
for k in range(1,n):
    #スタート位置を1ずつずらしてそれぞれ実行
    for i in range(k):
        height = 0
        correct = 0
        for j in range(i,n,k):
            if(height != h[j]):
                correct = 0
                height = h[j]
            correct += 1
            ans = max(correct,ans)

print(ans)
```

見てわかる通り、ほとんど解説の問題Ｘのコードと変わりませんね。
冷静になれば、全探索で出来る問題でしたね・・・・。

# 締め
ここまで見てくださりありがとうございました。
質問・ご指摘等ございましたら、コメントしていただけると幸いです。


# おまけ
**ここからは、今回の解説に関係ない部分ですので、興味ない方は、読み飛ばしてください。**

今回、私はこの問題を解く上で考察をミスりました。
私は、「**同じ数字同士で分けてから考える**」という解説とは真逆の方法でやってしまいました。
hの値が３０００以下ということで、「いける！」と思ってしまいました。

とりあえず、そのコード見せます。
```python:Wrong_Answer
n = int(input())
h = list(map(int,input().split()))

same = [[] for _ in range(3001)]

for i in range(n):
    same[h[i]].append(i)

ans = 1
for i in range(3001):
    if(len(same[i]) > 0):
        dic = {}
        hai = same[i]
        for j in range(len(hai)):
            for k in range(j + 1,len(hai)):
                tmp = dic.get(hai[k] - hai[j],[])
                tmp.append(hai[j])
                dic[hai[k] - hai[j]] = tmp
        for j in dic.keys():
            retu = dic[j]
            tmp = 2
            tar = retu[0]
            for k in range(1,len(retu)):
                if(retu[k] - tar > j):
                    ans = max(ans,tmp)
                    tmp = 2
                    tar = retu[k]
                elif(retu[k] - tar == j):
                    tmp += 1
                    tar = retu[k]
                #ここでミス
                elif(retu[k] - tar < k):
                    continue
            ans = max(ans,tmp)
print(ans)
```

それで、このコードがどうなったかというと、
![スクリーンショット 2024-12-21 235612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3740708/b73483b9-ac65-2804-4401-e5e9b154e61f.png)
WA1。何度も見たことある悪夢の光景ですね。

では、何故間違えてしまったかというと、コード内の「#ここでミス」ですね。
この部分では、K=3の赤色で１と書かれた７の部分のような場所を飛ばすためのものですね。
もし、コードがこの後も続くとしたらK=3の時のみにこの７の後に７が続く場合、ansの値が１足りず、誤答になってしまいます。

これに気付いて色々やりましたが、無理でした。もし数字で分けて考える方法で出来た人がいたら教えてほしいです。
・・・多分根本の考察ミスってるから無理な気がするんですよね。

もしかしたら、誰かの役に立つかもしれないのでおまけとして書かせていただきました。
ここまで読んで下さり本当にありがとうございました。
【Java】JSPについてざっくり

## JSPとは
Javaを使用して動的なWebページを作成するためのサーバサイド技術。
JSPとサーブレットの違いは以下。

JSP→HTMLの中にJavaを書く
サーブレット→Javaの中にHTMLを書く


## JSPのライフサイクル
1. 初期化(jspInit())
インスタンス化時に一度実行

2. サービス処理(_jspService())
JSPに対するリクエストを処理

3. 消滅処理(jspDestroy())
JSP停止前に実行される処理

## コメント
JSPでは以下のようにしてコメントを記載できる。

```
<!-- HTMLのコメント -->
<%-- JSPのコメント -->
```

## スクリプトタグ
### スクリプトレット
JSP内で有効なJavaコードを記載。
```
<% Javaコード %>
```

### 宣言
JSP内で有効な実数・メソッドを記述。
```
<%! 宣言 %>
```

### 式
JSP内で有効な式を記述。
```
<%= 式 %>
```

## ディレクティブタグ
WEBコンテナがJSPファイルを処理する際に必要な情報を設定する。

### paegディレクティブ
JSPファイル全体の環境を設定。

```
<%@ page 属性="値" %>
```

指定できる属性は以下。
1. **language**…javaのみ指定可
2. **import**…importするクラスのパッケージを指定
3. **session**…セッションオブジェクトを使用するか
4. **contentType**…MIMEタイプとエンコーディング方式を指定
5. **pageEncoding**…エンコーディング指定
6. **errorPage**…例外発生時にフォワードするURL
7. **isErrorPage**…エラーページであるか指定
8. **isELIgnored**…EL式の有効無効

スコープは現在のJSPファイル内であれば参照可。

### includeディレクティブ
翻訳時にインクルードするファイルを設定。
```
<%@ include file="Footer.html" %>
```
指定できる属性は以下。
1. **filee*…インクルードするファイルのURL指定

### taglibディレクティブ
JSPが使用するタグライブラリーを指定。

## 定義済オブジェクト
### request
クライアントからのリクエスト情報。スコープは1つのリクエスト内で参照可。
```
<%= request.getParameter("name") %>
```
### session
クライアントごとの情報。スコープは1つのセッション内で参照可。

```
<%= session.getAttribute("name) %>
```

### out
Webブラウザの返信に使用
```
<% out.println("Hello") %>
```

## アクションタグ
サーバーサイドで特定の処理を実行するために使用されるタグで、JSPページ内で動的な動作を簡潔に記述する手段を提供する。

### jsp:include
別のJSPやHTMLファイルの内容を現在のページに動的にインクルードする。

```
<jsp:include page="リソースのパス" />
```

### jsp:forward
現在のリクエストを別のリソースに転送する。
```
<jsp:forward page="リソースのパス" />
```

### jsp:useBean
JavaBeanを使用するために宣言する。
```
<jsp:useBean id="beanName" class="パッケージ.クラス名" scope="スコープ" />
```

### jsp:setProperty
jsp:useBeanで宣言されたJavaBeanのプロパティに値を設定する。
```
<jsp:setProperty name="beanName" property="プロパティ名" value="値" />
```

### jsp:getProperty
JavaBeanのプロパティの値を取得し、表示する。

```
<jsp:getProperty name="beanName" property="プロパティ名" />
```

### jsp:plugin
アプレットやプラグインコンテンツをWebページに埋め込む。

```
<jsp:plugin type="applet" code="コード名" width="幅" height="高さ" />
```

### jsp:param
パラメータを設定してリソースに渡す。
```
<jsp:param name="パラメータ名" value="値" />
```
個人学習のメモ

# はじめに
　Reactを勉強してきて、reduxを使うとstate管理が簡単になると聞ききました。しかし、理解するのが難しいと言われたので後回しにしてましたが、今回reduxを使ってstate管理をやっています。正確にはreduxを簡単に設計して利用できるredux toolkitを使ってやってみました。
 　独学で勉強している初心者であるため、間違っている内容が多い可能性があるのでご指摘いただくと幸いです。


# 開発状況
- バックエンド: Node.js + express + typescript
- フロントエンド: React + typescript + tailwind

# redux toolkitを使ってGoal作成の実装
　今回作っているものとしては、始める際に何から手を出せばわかない状態の時、目標(Goal)を作成し、それに対する詳細な計画(Plan)を立て、もっと詳細なタスク(Task)を立てて管理できるものになります。その中のGoal作成の部分をredux toolkitを利用して実装しました。

 # 実装
 ### stateの初期状態を定義
 ```
 const initialState: GoalState = {
  goals: [], 
  selectedGoal: null, 
  loading: false, 
  error: null, 
};
```
この`initialState`は、Goalに関連するすべての状態を管理するための初期値を定義しています。今回のコードは以下のように状態を管理します。
- goals: ユーザーが作成した目標を配列形式で管理します。
- selectedGoal: 現在選択した目標を保持します（後で目標(goal)を選択し、目標の細分化する計画(plan)を作成する予定です）。
- loading: API通信中にtrueに切り替わり、通信が完了するとfalseに戻ります。これによりローディングを表示できます。
- error: エラーが発生した場合に、そのメッセージを表示するために使います。

### Goal作成の非同期処理
```
export const createGoal = createAsyncThunk<
  IGoal, // ReturnedType: サーバーから返される完全なデータ型
  GoalFormInputs,
  // ThunkArg: サーバーに送信するデータ型
  { rejectValue: ErrorResponse } // ThunkApiConfig: エラーレスポンス型
>("goal/create", async (goalData, { rejectWithValue }) => {
  try {
    const response = await axiosInstance.post(`api/goal/create`, goalData);
    return response.data.newGoal;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      return rejectWithValue(error.response?.data as ErrorResponse);
    } else {
      return rejectWithValue({ message: "予期しないエラーが発生しました。" });
    }
  }
});
```
- `createAsyncThunk`
    - 非同期処理を簡潔に定義できるRedux Toolkitの機能です。
    - 第一引数でアクション名、第二引数で非同期関数を指定します。

- APIリクエスト
    - axiosInstance.postを使い、api/goal/createエンドポイントにデータを送信します。
    - `axiosInstance`とはAxiosのインスタンスを作成し、リクエストを簡略化するための仕組みになります。
    - `axiosInstance`については今後整理したいと思います。

### Redux Sliceの作成
```
const goalSlice = createSlice({
  name: "goal", // Sliceの名前（
  initialState, // 初期状態
  reducers: {}, // 同期処理用のReducer
  extraReducers: (builder) => {
    builder
      .addCase(createGoal.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(createGoal.fulfilled, (state, action) => {
        state.loading = false;
        state.goals.push(action.payload); Goalを追加
      })
      .addCase(createGoal.rejected, (state, action) => {
        state.loading = false; 
        state.error = (action.payload as ErrorResponse).message; 
      });
  },
});
```
- `createSlice`の役割は状態とReducerを一括管理します。
- extraReducersの構成
    - createAsyncThunkの状態（pending, fulfilled, rejected）に応じて、stateを更新します。

- pending:
    - 非同期処理が開始された際に、loadingをtrueにしてローディング状態を表現。
    - エラーをリセットして、以前のエラーを消去。
- fulfilled:
    - 非同期処理が成功した場合、loadingをfalseに戻します。
    - サーバーから返ってきたデータをgoalsに追加します。
- rejected:
    - 非同期処理が失敗した場合、loadingをfalseに戻します。
    - サーバーから返されたエラーメッセージをerrorに格納します。

# まとめ
　今回はじめてRedux toolkitを学習して適用してみました。時間がかかりましたが、これからreduxを使って状態管理ができるように頑張ります。
 　次回は、Goalの選択や詳細表示の実装、さらには計画（Plan）やタスク（Task）の管理機能を実装したいと考えています。
【JavaScript】class構文とnew演算子について（勉強）

javascriptについて勉強しているとnew演算子とclass構文で躓いたので自分メモ用にまとめてみる。
（書籍やWEBサイト、chatGPTで調べたものをまとめています。）
間違いがあったら教えていただけると嬉しいです。

### 対象者
* javascriptのclass構文やnew演算子について学んだが、それぞれの関係性、必要性がわからない方

## class構文は設計図を定義している（だけ）
実際にオブジェクトを作るものではない（classだけではオブジェクトは存在していない）
⇒仮に車の設計図だったとして、設計図だけあっても車は動かない。
コンストラクタ[^1]やメソッド[^2]の定義をする時に使われる。

例：
```javascript
class Robot {
  constructor(name) {
    this.name = name;
  }

  hello() {
    console.log(`こんにちは、私は${this.name}ロボです！`);
  }
}
//定義しただけであって、オブジェクトは存在していない
```
【その他特徴】
* ES2015から導入されたもの（それまでは関数を使って対応していた）
* データ型は関数

classについては、[モダンスタイルによる基礎から現場での応用まで　JavaScript本格入門](https://gihyo.jp/book/2023/978-4-297-13288-0)で以下のように補足説明されている。
>より正しくは、JavaScriptにはクラス/インスタンスという区別は存在しません。
>JavaScriptにあるのはオブジェクトだけであり、あるオブジェクトをプロトタイプ（雛形）として別のオブジェクトを定義するのが基本です。
>～中略～
>ただし、ES2015のクラスは、あくまでプロトタイプをらしく見せるための糖衣構文（シンタックスシュガー）にすぎません。


## new演算子はclass（設計図）に基づいてオブジェクトを作る
設計図をもとに実際のオブジェクトを作るための仕組み
⇒設計図があったとして、newがあれば車を作れる（オブジェクト化）

例：
```javascript
const robot1 = new Robot("ABC");

// robot1 という実際のオブジェクトに対してメソッドを呼び出せる
robot1.hello(); // こんにちは、私はABCロボです！

```
## 補足
### シンタックスシュガー（糖衣構文）とは
<b>⇒　やっていることは同じだけど、より読みやすく、書きやすくした方法</b>
上記で書いた通りJavaScriptのclassはES2015から導入されたものなので、それ以前は別の方法で作っていた。
```javascript
// 「class」のない時代のやり方（コンストラクタ関数とプロトタイプ）
function Robot(name) {
  this.name = name;
}

Robot.prototype.hello = function () {
  console.log(`こんにちは、私は${this.name}ロボです！`);
};
```
やっていることは同じだが、もっと見やすくしたものがclass構文。

:::note info
理解した内容
classとnewはお互いに必要な存在
:::

[^1]::「インスタンスの生成と初期化」のための特殊なメソッド
[^2]:オブジェクト内で定義された関数
【UiPath】OCから同一プロセスが同時に実行されないよう制御する

一つのプロセスを複数のマシンに紐づけどこからでも実行できるようにしたが、アクセスするリソースが同じなどの理由から同時には動かしてほしくない、そんな時の実装。OC側でも制御出来そうだが、今回はxaml側に設定する。

## 実装
コード全体がこちら。
OCにアクセスして実行中のジョブを取得し、自身と同じプロセス名のジョブが2件以上実行中であればエラーにするという仕組み。この仕様上、同タイミングに両方開始された場合はどちらもエラーになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/584879e0-0848-c5d5-4256-05f4046a7216.png)

「ジョブを取得」のフィルターで「ステート = Running」の設定を行い、実行中のジョブだけ取得する。余談だがここの設定はビルダーが実装されたお陰で昔に比べだいぶ簡単になった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/8e70aa72-7ef6-b738-a681-1d44322853a8.png)

「ジョブを取得」は`OrchestratorJob`変数をコレクションで、「現在のジョブの情報を取得」は`CurrentJobInfo`変数を単体で返す。型は違うが、どちらも`.ProcessName`メソッドでプロセス名を取得することができる。

あとは、繰り返しアクテビティで「ジョブを取得」が返したコレクションの中に「現在のジョブの情報を取得」で取得した自身のプロセス名と同一のジョブが何件あるかを探査する。結果が1件であれば実行されてるのが自身のジョブだけ、2件以上あれば自身以外にも同一のプロセス名のジョブが実行されているということになる。

## 参考
https://docs.uipath.com/ja/activities/other/latest/workflow/get-jobs

https://docs.uipath.com/ja/activities/other/latest/workflow/get-current-job-info
【Advent Calendar 2024 #13日目】AWS学習〜生成AI/ML編〜 ニューラルネットワーク

# はじめに
本記事は、「初めての一人アドベンドカレンダー2024 by hohe」の13日目の記事となります。13日目はニューラルネットワークについてまとめます。

# 代表的なニューラルネットワーク

## CNN (Convolutional Neural Network)
CNN(Convolutional Neural Network, 畳み込みニューラルネットワーク)は、主に画像分野に用いられるニューラルネットワークの１種です。主な層としては、畳み込み層、活性化層 (ReLU 層)、プーリング層の３つがある。

### 畳み込み層
畳み込み層では、入力画像とは別にカーネルというフィルタのような重み行列を用意します。カーネルを左斜め上から入力行列の全ての位置に移動させ、加重和を計算することで出力する。

### プーリング層
畳み込み層で得られた特徴マップを圧縮する。

## RNN (Recurrent Neural Network）
過去の情報を利用して現在および将来の入力に対するネットワークの性能を向上させ、主に時系列データや自然言語処理に用いられるニューラルネットワークの１種です。

### 中間層
RNNでは中間層で計算した情報を、再び中間層の入力として繰り返し処理を行う回帰的な仕組みをとることで、時系列を持ったデータや言語などの連続的なデータを扱うことができます。

### RNNの問題点
RNNで用いられている数式の特性上、計算を数多く繰り返している途中で正しいデータとの誤差が限りなく0に近づき、学習が止まってしまうという問題点（勾配消失）があります。そのため、これを改良したLSTM（Long Short-Term Memory）があります。
【Rspec】ケース別、よく使った書き方まとめ

~~ネタ切れ感満載ですが~~

# 1.before doとlet
コンテキストごとに同じインスタンスを作るが、一部のデータは可変にしたいとき

```ruby
# これを
context '1' do
  let(:hoge) { create(:hoge, fuga_id: 100) }
end

context '2' do
  let(:hoge) { create(:hoge, fuga_id: 200) }
end

# こう
let(:fuga_id) { 100 }

before do
  create(:hoge, fuga_id: fuga_id)
end

context '1' do
end

context '2' do
  let(:fuga_id) { 200 }
end
```

# 2.Timecop
テスト実行時に現在時刻を固定したいとき

```ruby
before do
  Timecop.freeze(Time.local(2024, 12, 21))
end

after do
  Timecop.return
end

it "2024であること" do
  expect(Time.now.year).to eq(2024)
end
```

# 3.allow
メソッドをモックしたいとき

```ruby
it "100を返すこと" do
  allow(HogeModel).to receive(:hoge_method).and_return(100)
  expect(HogeModel.new.hoge_method).to eq 100
end
```

# 4. and_return
モックしたメソッドが複数回呼ばれていて、返り値を毎回指定したいとき

```ruby
  allow(Order).to receive(:find).and_return(1, 2)

  expect(Order.find).to eq(1)
  expect(Order.find).to eq(2)
end
```

# おわりに
テストデータを作るのが一番大変かも
【React】編集可能なテーブルコンポーネントの実装

## 目的
Excel ライクな、セルの編集が可能なテーブルを実装していきます。

## サンプル
実装についての説明の前に、どの様なものができるかを確認されたい場合は、
サンプルページを以下のページで公開してあるので、ご確認ください。

https://nagajun1.github.io/sample_react_ts/datasheet

上記サンプルページの実装のためのコードは、以下ページで公開してあります。

https://github.com/NagaJun1/sample_react_ts/blob/main/src/pages/DataSheet/DataSheet.tsx

## 使用ライブラリ
`AG Grid`を使用させていただいています。

https://www.ag-grid.com/javascript-data-grid/getting-started/#your-first-javascript-data-grid

## インストール
以下コマンドでライブラリをインストールします。
```
npm install ag-grid-react
```

## 実装コード
```Page.tsx
import { AgGridReact } from "ag-grid-react";
import { ColDef, ClientSideRowModelModule, ModuleRegistry, TextEditorModule, NumberEditorModule, CheckboxEditorModule, ValidationModule } from "ag-grid-community";

/** 編集可能なテーブル表示コンポーネント */
export const DataSheet = () => {
    ModuleRegistry.registerModules([
        ClientSideRowModelModule,
        NumberEditorModule, // number テキスト編集を有効にするための Module
        TextEditorModule, // string テキスト編集を有効にするための Module
        CheckboxEditorModule, // チェックボックスを使うためのオプション
        ValidationModule /* Development Only */,
    ]);

    return (
        <>
            <div style={{ height: 500 }}>
                <AgGridReact
                    columnDefs={columns}
                    rowData={rowData}
                    onCellValueChanged={(e) => {
                        // セルの編集イベント
                        console.log(e)
                    }}
                />
            </div>
        </>
    );
}

/** 列定義 */
const columns: ColDef[] = [{
    headerName: "列ヘッダー名",
    field: "a",　// rowData に紐づけるフィールド名
    // cellEditor: "agCheckboxCellEditor", // チェックボックスで表示・編集するオプション
    width: 100,
    editable: true,
}, {
    headerName: "列ヘッダー名",
    field: "b",
}];

/** セルに表示するデータ */
const rowData = [{
  a: 100,
  b: 120,
}, {
  a: 220,
  b: 140,
}];
```

## 解説
列定義は`columnDefs`、一覧に表示するデータは`rowData`に登録します。
列を編集可能にするには、`ColDef`で`editable: true`を設定します。
※`ModuleRegistry`に Module の登録漏れがあると動作しません。

実際の画面での編集時は、セルを Wクリックすることで編集可能です。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/7e562589-fa4a-b39f-f31d-c0624df4f497.png' width='400' />

サンプルでは雑な実装しか行っていませんが、セルの変更時のイベントを検知したい場合は、`onCellValueChanged`を使用します。
サンプルページでは、変更時にコンソール出力される様になっています。

その他、サンプルの実装に組み込んでありますが、`cellRenderer`に Reactコンポーネントを書き込むことで、セル内にコンポーネントを表示することが可能です。
GithubにおけるSSH接続について

# GithubにおけるSSHキーの取得について
備忘録、最近OSを初期化することが多いので、GithubのSSH接続ついてメモしておく
OS: wsl ubuntu

# 新しい SSH キーを生成する
[ターミナル] を開く。

以下のテキストを貼り付け、例で使用されているメールを GitHub メール アドレスに置き換える。

```
$ ssh-keygen -t ed25519 -C "your_email@example.com"
```
以下のメッセージが出現。
```
> Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/sophytoeat/.ssh/id_ed25519):
```
どこにsshキーを保存するかを聞かれる。こだわりがなければそのままエンターを押す。

```
> Enter passphrase (empty for no passphrase):
Enter same passphrase again:
```
パスワードの作成を要求される。セキュリティ上の問題がなければそのままエンターを押す。
```
> Enter passphrase (empty for no passphrase): [Type a passphrase]
> Enter same passphrase again: [Type passphrase again]
```
ここも特にセキュリティ上の問題がなければエンター。

# SSH キーを ssh-agent に追加する
ssh-agent に新しい SSH キーを追加してキーを管理する前に、既存の SSH キーを確認し、新しい SSH キーを生成しておく。

バックグラウンドでssh-agentを開始します。
```
$ eval "$(ssh-agent -s)"
> Agent pid 59566
```
SSH プライベートキーを ssh-agent に追加。

```
$ ssh-add ~/.ssh/id_ed25519
```

# 公開鍵をGithubに貼り付ける。

下記のコマンドで公開鍵を出現させる。
```
$ cat ~/.ssh/id_ed25519.pub
```
公開鍵をコピーしてGithubの「New SSH key」に貼り付け。
これでGithubへのSSH接続が完了。

# P.S
```
> Are you sure you want to continue connecting (yes/no[fingerprint])?
```
上記の回答にはyesを入力するように。他の選択肢を選ぶとverificationは失敗する。
Oracleでオプティマイザ統計(統計情報)が取得されていることや、取得時間を確認したい

# この記事について
DBMSで、統計情報からコストを算出し、適切な実行計画を選択します。

インデックス貼っているのにフルスキャンが走っている！といった際は統計情報が不適切かもしれません。

Oracleで統計情報が適切か否かを調べる方法をまとめます。

# DBA_TAB_STATS_HISTORYを参照し、統計情報の更新がされているか確認
下記のクエリを叩くと、新しい順で表ごとの統計情報の更新の履歴が確認できます。

```sql
SELECT * FROM DBA_TAB_STATS_HISTORY ORDER BY STATS_UPDATE_TIME DESC;
```

`STATS_UPDATE_TIME`を見ると、いつ表の統計情報が更新されているかを確認できます。この更新日時が古い場合や存在しない場合は統計情報が更新されていない可能性があります。

https://docs.oracle.com/cd/E57425_01/121/REFRN/GUID-4E121B87-0064-4CC5-8259-6BECE2F88B78.htm

# DBA_TAB_STATISTICSを参照し、表の統計情報がいつ更新されているのか確認する
以下のクエリでオブジェクトごとの統計情報を取得します。
```sql
SELECT * FROM DBA_TAB_STATISTICS WHERE OWNER LIKE '自分が取得したい表のOWNER';
```

WHERE句は良い感じに自分の欲しいオブジェクトを絞れるように適宜変えてください。

`NOT IN ('SYS', 'SYSTEM')`とかだけでも十分絞れそうです。

取得結果の`STALE_STATS`と`LAST_ANALYZED`を参照します。

`STALE_STATS`は以下3つの値を取ります。この列がYESかnullの場合は、統計情報が適切でない可能性が高いです。
- YES：統計情報が失効している
- NO：統計情報が失効していない（有効）
- null：統計情報がそもそもない

`LAST_ANALYZED`は表が分析された最新の日付が入ります。この列の値がnullの場合も、統計情報が適切ではない可能性が高いです。

https://docs.oracle.com/cd/E57425_01/121/REFRN/GUID-03D846F8-5906-42FE-983B-E3434F5545A7.htm

https://docs.oracle.com/cd/E82638_01/tgsql/gathering-optimizer-statistics.html#GUID-33C8239F-53A9-4FCB-969B-4772041317AAf

# 統計情報を取得したコマンドを確認する
大体の場合統計情報を取得するコマンドは分かると思います。もしコマンドが分からない場合は下記SQLで推察できるかもしれません。

以下コマンドでSQLのテキストに「STAT」が含まれるものを取得できます。これで「DBMS_STATS.GATHER_SCHEMA_STATS」があれば、コマンドの内容が見れると思います。
```sql
SELECT
  *
FROM
  DBA_HIST_SQLTEXT
  INNER JOIN DBA_HIST_ACTIVE_SESS_HISTORY ON DBA_HIST_SQLTEXT.SQL_ID = DBA_HIST_ACTIVE_SESS_HISTORY.SQL_ID
WHERE
  SQL_TEXT LIKE '%STAT%';
```

https://ddocs.oracle.com/cd/E16338_01/server.112/b56311/statviews_4053.htm

https://docs.oracle.com/cd/E16338_01/server.112/b56311/statviews_3201.htm
転職活動を通して得た学び：社外に目を向けることの重要性

# 概要

今年転職しました。初めての転職で、苦戦して長期戦となりました。その原因は、社外に目がいかず、客観的な視点がなかったことかなと感じています。これは、自分の強みや市場価値がわからないことにも繋がってしまいます。エンジニアとして仕事をこなして、社内で評価を受けていくのももちろん重要ですが、他のエンジニアの様子を知ることも重要です。自分の強みや可能性に気づくことや、自分の市場価値を把握して立ち回りを考えていればより良い転職活動だっただろうと思いました。今回の転職活動をまとめる意味も兼ねて、「これをやっていれば.../やってよかった」をシェアします。誰かの転職活動のヒントになれば幸いです。

## 背景と転職理由

### 入社後の様子

新卒入社後、8年目ぐらいまでは転職を全く考えていませんでした。入社直後においては、自分のプログラミングスキルは同期よりも高く、すぐに開発に参画できていました。そのせいか、会社からは高い評価をされていましたし、特に大きな不満はありませんでした。
社内でうまくいっていたせいなのか、自分はあまり社外に目がいきませんでした。自分の市場価値を確かめることや、他社のエンジニアから刺激を受けることなどがありませんでした。ただ、エンジニアとしてシステム開発やプログラミングは好きで、与えられた仕事の範囲で工夫したり、必要に応じて勉強するなど自発的に活動はしていました。
気づいたら、あっという間に。8年ぐらい経過していました...。

### 転職理由

長い年月が経つと、会社の経営方針などもありました。徐々に自分の能力を十分に活かせない仕事が増え、業務が固定化・属人化していきました。そのせいで徐々に不満が大きくなっていきました。能力を活かせる仕事の増加を会社に働きかけましたが、実現しませんでした。開発経験は積みたいものの、現状維持に若干の物足りなさを感じはじめました。そこで、周りの先輩後輩、知人の勧めもあって、初めての転職活動を始めることにしました。

## 転職活動の過程と反省

### 転職活動してみたものの…

転職サイトに登録し、職務経歴書を作り、エージェントと会話したり、いくつか求人を送ってもらいました。その求人に応募するも面接はうまくいかず、書類は通るが1次面接でお見送りになる会社がほとんどでした。5〜6社このお見送り状態が続き、これ以上続けても埒が開かないと思い。体制を立て直すことにしました。知人に相談したり、他社のエージェントに変えてみたり、転職本を読んだりしました。

### 反省とその後

転職の面接では、自分の強みと求人との関連性を見つけ出し、自分の能力がこの求人に合致していて、ふさわしい人物だということを説明しなければならないはずです。当時の自分は以下の問題がありました。

- **アピールが弱い**
  - 自分の強みがはっきり分かっていない
  - 自分のどのスキルや能力が、市場価値として高く、アピール材料になるのか分かっていない
  - エージェントが推奨してくる求人を見てもピンと来ず、アピールできる自身の能力や経験を説明できない
  - 求人から、どのようなスキルや経験が必要とされているのか読み出せない
- **プレゼン能力が低い**
  - 自分の能力を客観的に説明できない
  - 自分を売り込む説明ができない

プレゼン能力は練習すれば改善できるとして、アピールが弱いというのはおかしいです。どこの企業も同じような仕事があるはずで、同じようなことで悩んでいるはずです。社内で評価が良かったということはそれほど仕事をしてきたはずで、いろいろな経験があるはずです。アピールできることはたくさんあるはずなのに、それができませんでした。その後、1年ほど考え直し（こんなに長く中断するつもりはなかった…）、上記のようなことをある程度改善したうえで活動再開し、最終的に転職できました。

## 転職活動をしてみて

### やっておけばよかったこと

「これをやっておけばよかった」こととして「社外に目を向けること」があげられます。具体的には、常日頃から以下のことを実施し、定期的に他のエンジニアと自分を見比べることで、客観的な視点を手に入れることです。他社と自分を比べることで、自分の強みや市場価値が分かっていき、「こういう経験がこのアピールに使える」「この求人にこういうアピールが刺さる」ということが分かってくるのだと思いました。

- **様々なエンジニアがいることを知る**
  - 具体的には技術系記事の閲覧や執筆、カンファレンスへの参加などを行い、他のエンジニアの活動や成果、能力、心がけ、ノウハウ、信条、勉強法などを参考にする
  - 周りのエンジニアの活動や考え方に触れることで、自分がどのようなエンジニアなのか、客観的な視点が手に入ることで、市場価値の把握やアピールポイントの強化に繋がる
  - 自身の立ち位置や目指すべき方向性を知るきっかけになる
- **幅広い興味を持つ**
  - さまざまな事柄に触れて、他のエンジニアの活動を知ることにもつながる
- **もっと多くのカジュアル面談をする**
  - 求人の求める人物像や詳細の掘り下げができるため、自分の経験をどのようにアピールすれば一番よさそうか計画を立てることができる
  - その会社にいるエンジニアの様子を知ることができ、客観的な視点を手に入れることができる。また、面接官が、エンジニアの場合もある

### やってよかったこと

失敗の多い転職活動でしたが、以下のように、やってよかったことも少なからずあるかなと思います。

- **焦らず十分に検討したこと**
  - 精神的な余裕を持って活動できたことで、後悔のない選択に繋がった。途中1年ほど中断せず続けていたら、後悔の残る転職活動となっていた可能性がある
- **複数のコネクション（エージェント、先輩、友人など）を活用・検討**
  - 情報収集の幅が広がり、客観的な評価を得ることに繋がった
- **記録を取ったこと**
  - 当時どのようなことを考えていたかがわかる
  - 自分の成長を感じることができる
  - 後々反省するときに使え、問題改善に活用できた

以上です。
回文エディタ

今日、12月21日は「12/21」とも書く。
これは回文である。
そこで、回文が作りやすくなる？エディタを作ってみた。

# 仕様

1. 文字列の入力を受け取る
2. 入力された文字列と、それを反転させた文字列を繋げて表示する

# 文字列を文字に分割する

JavaScript では、文字列を UTF-16 のコードポイントの列として扱う。
そのため、何も考えずに文字列を反転させようとすると、**サロゲートペア**を破壊して変な表示になってしまうことがある。
さらに、サロゲートペアを考慮しても、絵文字などの合成文字を破壊してしまう可能性が残る。

確か、文字列を見た目通りの文字に分割するライブラリがあっただろうと思い、AIに聞いてみた。

[Perplexity AI: JavaScript で、文字列をUnicodeの合成とかを考慮して人間にとって自然な文字単位に分割するライブラリあったよね。なんてやつだっけ？](https://www.perplexity.ai/search/javascript-te-wen-zi-lie-wouni-UaUdJ6piRLeQxzCNJ_amLQ) ([魚拓](https://megalodon.jp/2024-1221-2148-02/https://www.perplexity.ai:443/search/javascript-te-wen-zi-lie-wouni-UaUdJ6piRLeQxzCNJ_amLQ))

すると、なんと今は主要ブラウザの標準機能でできることがわかった。(Firefox では今年 (2024年) 4月かららしい！)
具体的には、[Intl.Segmenter](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter) を用いる。

まず、[コンストラクター](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/Segmenter)で `Intl.Segmenter` のオブジェクトを生成する。
引数なしで呼び出すと、文字列を文字単位で分割する設定になる。

次に、このオブジェクトの [`segment()`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/segment) メソッドを用いることで、文字列を文字単位に分割できる。
このメソッドは、分割した文字に加えてその他の情報も格納されたオブジェクトの列 (反復可能オブジェクト) [`Intl.Segments`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/segment/Segments) を返す。
これを [`Array.from`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/from) メソッドで配列に変換し、[`map()`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map) メソッドでオブジェクトから `segment` メンバを取り出すことで、文字の配列が得られる。

このオブジェクトを用いて、
[JavaScript Text Character Splitting (1文字毎に分解) #文字列 - Qiita](https://qiita.com/yoya/items/636e3992ec45c1c40c14)
に乗っているサンプルの文字列を文字に分割してみる。

```javascript
const inputString = 'A01赤-葛󠄀城市😄👨‍👩‍👧‍👦!';

const segmenter = new Intl.Segmenter();
const chars = Array.from(segmenter.segment(inputString)).map((s) => s.segment);

console.log(JSON.stringify(chars));
```

これを実行すると、

```text
["A","0","1","赤","-","葛󠄀","城","市","😄","👨‍👩‍👧‍👦","!"]
```

と出力され、複数の文字を合成した絵文字を含む文字列を正しく文字に分割できていそうであることがわかる。

# 配列を逆順にする

[`concat()`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) で配列のコピーを取り、[`reverse()`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) を用いることで、配列を逆順にできる。
最近のブラウザでは [`toReversed()`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed) メソッドも使えるようだが、この方法のようがより幅広い環境で動くだろう。

# 成果物

[回文エディタ](https://mikecat.github.io/kaibun_editor/)

![回文エディタのスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/67f6e41c-24a7-5df1-4e98-811cd690cf89.png)

プロジェクトページ：[mikecat/kaibun_editor: Show entered string plus reversed one.](https://github.com/mikecat/kaibun_editor)

# おわりに

これを用いることで回文の検証はしやすくなるかもしれないが、回文を思いつくのは難しいかもな…
React 19のリリース

# はじめに
以前にアプリ開発にReact 18を使用したことがありましたが、いつの間にかReact 19がリリースされていましたので、興味がてら違いを調べてみました。

https://ja.react.dev/

# Reactとは
Facebook社が開発したWebサイトやWebアプリのUIを構築するためのJavaScriptライブラリです。
### 主な特徴
- 宣言的にコードを記述可能
- コンポーネントベースのUI構築
- 仮想DOMによる効率的なレンダリング

# 変更点
- アクション (Action) の追加
- useActionStateフックの追加
- React DOM：<form> アクションの追加
- React DOM の新しいフック：useFormStatusの追加
- 新しいフック：useOptimisticの追加
- 新しい API：useの追加
- 静的サイト用の新 DOM API（prerender、prerenderToNodeStream）の追加
SimpleWebAuthnのExampleからコードの流れを追ってみた

## SimpleWebAuthnのExample

https://github.com/MasterKale/SimpleWebAuthn/tree/master/example

## `/puclic/index.html` (クライアント側)
### 登録時
1. `fetch('/generate-registration-options')`
1. `SimpleWebAuthnBrowser.startRegistration`
1. `fetch('/verify-registration')`

### 2回目以降の認証時
1. `fetch('/generate-authentication-options')`
1. `SimpleWebAuthnBrowser.startAuthentication`
`useAutofill: true`は自動で認証器を選択し、チャレンジを促す
1. `fetch('/verify-registration')`

## `index.ts` (サーバー側)
### `/generate-registration-options`
認証器を登録するためのオプション生成

### `/verify-authentication`
ブラウザや認証器から送られてきた認証レスポンスをサーバー側で検証

### `/generate-authentication-options`
登録済みの認証器を使って、ユーザーを認証するためのオプションを生成
[forensics] I_wanna_be_a_streamer (WaniCTF 2024) writeup

---

- Source: WaniCTF 2024
- Author: [kaki005](https://github.com/kaki005)

--- 

pcapファイルが与えられる。

wiresharkで開くとSSDP, TCP, RTPプロトコルの通信が目に付く。特に最初と最後以外のほとんどがRTPプロトコルでの通信になっている。

RTPは[Real-time Transport Protocol](https://ja.wikipedia.org/wiki/Real-time_Transport_Protocol)のことらしい。つまり、動画か音声かそれに類するものだと推測。

wiresharkでRTPの抽出はできたが、音声だけ取得できてもflagはなく、何も嬉しくない。一応送信元と送信先の情報は得られた。
![{07F0C5D1-19B6-4BC0-85FF-4E81802D5724}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982709/74723f05-c1a6-2c40-5190-01298635fbd4.png)

[H264を抽出するwiresharkのプラグイン](https://github.com/volvet/h264extractor)があったので入れる。RTP payload typeを96に設定する。
![{11D8FE66-8ACD-464A-B76C-3DE2EB796B44}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982709/c91a143a-e03b-decd-f3b6-4aaed31e32a0.png)

抽出すると`.264`という拡張子のファイルが生成された。

そのままでは再生できないので[適当なオンライン変換サイト](https://video-converter.com/)でmp4にコンバートする。

得られた動画を再生するとflagを見ることができた。
![{6ACF26B1-DBCB-4ACF-B76A-15A443FF974D}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982709/221f9d9a-e9c3-4592-ff39-ccf5caae0c0c.png)
`FLAG{Th4nk_y0u_f0r_W4tching}`
{作成}Ollamaとllava-phi3(vision)の精度検証とtesseract-ocrの構築手順と実行

# tesseract-ocrの構築手順

環境
WSL2

# 手順
```
sudo apt -y install tesseract-ocr tesseract-ocr-jpn libtesseract-dev libleptonica-dev tesseract-ocr-script-jpan tesseract-ocr-script-jpan-vert
```
https://www.kkaneko.jp/ai/ubuntu/tesseract.html
or
```
sudo apt install tesseract-ocr libtesseract-dev tesseract-ocr-jpn
```
https://qiita.com/bluepost59/items/037d3815c89c5fcbfafe
```
tesseract a.png outbase -l jpn
```
```
cat outbase.txt
````
目次
Ollama Visionって何?

* Ollama Visionの使い方
Pythonライブラリから使う方法
JavaScriptライブラリから使う方法

この時点でも実行できるがPythonで実行する場合は
```
pip install pytesseract
```
が必要。
```python:コード１
from PIL import Image
import pytesseract

# Tesseractの実行ファイルパスを設定（必要な場合）
pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract'

# 画像からテキストを抽出
image = Image.open('a.png')
text = pytesseract.image_to_string(image, lang='jpn')
print(text)

```
```python:コード２
from PIL import Image
import pytesseract
import pyautogui

# Tesseractの実行ファイルパスを設定
pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract'

# 画像を開く
image = Image.open('a.png')

# テキストと座標情報を取得
data = pytesseract.image_to_data(image, lang='jpn', output_type=pytesseract.Output.DICT)

# 結果を出力
for i, text in enumerate(data['text']):
    if text.strip():
        x = data['left'][i]
        y = data['top'][i]
        print(f"テキスト: {text}, 座標: ({x}, {y})")
def click_text(target_text):
    for i, text in enumerate(data['text']):
        if text.strip() == target_text:
            x = data['left'][i]
            y = data['top'][i]
            print(f"{target_text}を座標({x}, {y})でクリックします")
            pyautogui.click(x, y)
            return
    print(f"{target_text}が見つかりませんでした")

# 使用例
click_text("目次")

```

# ollama + llava-phi3

## 手順
WSLで以下を実行しCtrl+Dで抜け出す
```
ollama run llava-phi3
```
```python:コード３
import ollama
prompt="""
Output the results of the analysis of the browser screenshot under the following conditions.
Condition 1: Read all text information.
Condition 2: Output text and information readable from the image other than text.
"""
res = ollama.chat(
    model="llava-phi3",
    messages=[{
        'role': 'user',
        'content': prompt,
        'images': ['./a.png']
    }]
)

print(res['message']['content'])
```

結果：日本語訳済み
読み取らせた画像1
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965944/33dc1d3c-35fe-0f2d-820c-fcfc23ba226f.png)



画像は紺色の画面に白い文字。画面に表示されている主な内容は、「HTTPB Writeup 」と書かれている。この見出しの下には、黒いテキストの空行が2行ある。画像の右側には、3つのグレーのアイコンがある小さなツールバーがある。これらのアイコンの位置はそれぞれ異なり、1つは右上隅、もう1つはその少し下、そして最後の1つは画面の下端に寄っている。これらのアイコンの正確な名前や機能は、この画像では見えない。

読み取らせた画像2
![c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3965944/0e60336a-1353-1df1-d2da-d3cc8330a2ac.png)

画像の左上の文字が切れていて、完全に読むことができない。画像の残りの部分には、「BACH 」や 「X-Tunnel 」など様々な情報が含まれている。右下にはウェブサイトのアドレスも見える： <https://www.xtunnel.com/>。

その他の視覚的な情報としては、画面上にいくつかのボタンがあり、ページをナビゲートしたり、対話したりするのに使われているようだ。さらに、「BACH 2016 」を示すテキストと、「2015」、「4.3%」などのデータに関連しそうな数字がいくつかあるように見えるが、文脈がなければその目的を判断するのは難しい。

## 結果
少し複雑になると読み込めないようだ。
【シリーズすごいぞiQ-F】マクロ型ファンクションブロックの引数について

## はじめに
プログラミングマニュアルプログラム設計編に以下の記述があります
**「マクロ型ファンクションブロックのプログラム本体以外では、ファンクションブロックの引数は使用せずに、引数引き渡しに使用したデバイス／ラベルを使用してください。」**
マクロ型の場合、ファンクションブロック型のラベルをプログラムの他の場所で使用しないという注意書きですが、内部的にどういう処理をしているのか調べてみました。

## 1．サンプルプログラム
用意したのは単純なプログラムなので特に説明はしません。

**マクロ型ファンクションブロックプログラム**
![ファンクションブロック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/63f630f3-f6e1-c43c-2079-d2728464cf96.png)

**メインプログラム**
![プログラム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/04a56e0c-4eb7-daea-4f1d-98c71c1a9140.png)

## 2．プログラム実行結果
マクロ型ファンクションブロックに直接引数を接続した方はプログラム中でファンクションブロック型のラベルを使用すると正常に動作していません。
直接引数を接続しない場合は特に問題なく正常動作しました。

![実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/4754d167-cdc1-6db8-7aa7-5d5c1af0202f.png)

## 3．プログラム変換結果を確認する
下記の2種類の変換結果を確認しました。
+ エディタ上の右クリックで表示する変換結果(V1.110Q以降）
+ プログラムファイルの照合結果での変換結果

**エディタ上の右クリックで表示する変換結果**


    0	*マクロ型FB引数指定
    1	LD M0
    1	OUT FbPou_1.i_b_label　　※FB型ラベルに出力しているようだがステップ増えてない
    1	FBCALL FbPou (FbPou_1)
    5	LD FbPou_1.o_b_label
    5	OUT M1
    5	LD FbPou_1.o_b_label
    7	OUT Y0
    9	LD FbPou_1.i_b_label
    11	OUT Y1
    13	*マクロ型FB引数無指定
    14	LD M0　　　　　　　　　　
    16	OUT FbPou_2.i_b_label　　※FB型ラベルへの出力でステップ増えている
    18	FBCALL FbPou (FbPou_2)
    22	LD FbPou_2.o_b_label
    24	OUT Y10
    26	LD FbPou_2.i_b_label
    28	OUT Y11
    30	END

**プログラムファイルの照合結果での変換結果**

    0	;*マクロ型FB引数指定
    1	LD M0　　
    3	OUT M1　　 ※FB型ラベルのメモリを介さずに処理が行われている
    5	LD LV:0.3  ※LV:0.3には何も代入されていない
    7	OUT Y0
    9	LD LV:0.2　※LV:0.2には何も代入されていない
    11	OUT Y1
    13	;*マクロ型FB引数無指定
    14	LD M0
    16	OUT LV:34.2　※FB呼び出し外でラベルメモリに出力
    18	LD LV:34.2
    20	OUT LV:34.3　※FBはラベルメモリで処理を行う
    22	LD LV:34.3　※ステップ16で値が代入されている　 
    24	OUT Y10
    26	LD LV:34.2　※ステップ18で値が代入されている
    28	OUT Y11
    30	END

V1.110Qで手軽に変換結果が表示されるようにはなったのですがマクロ型でもFBCALLが記述されていたりと、中間ファイルと受け取れば良いのかという結果が表示されます。

シーケンサに書き込まれる変換結果は「オンライン-照合」から確認できます。
ラベルはラベルメモリアドレスで記述されるので解読は難しくなります。
マクロ型ファンクションブロックは平文のプログラムに書き直されています。
ファンクションブロックの呼び出しで引数を直接指定した場合、インプットとアウトプットのラベルメモリには引数に引き渡したデバイスが直接記述されていました。
これではプログラムの他の部分でファンクションブロック型ラベルを参照しても何も値が入っていません。

ファンクションブロックの呼び出しで引数を直接指定しない場合はラベルメモリを介して処理が行われていました。
ですので、プログラムの他の部分でファンクションブロック型ラベルの参照が可能になります。


## おわりに
いままで、マニュアルの注意書きが気持ち悪く感じてマクロ型ファンクションブロックの使用は考えていなかったのですが、スキャンタイムを考慮する必要がある分野では無視できないと考えて調べてみました。

結論としては、
**「ファンクションブロックの呼び出しに直接引数を記述しなければサブルーチン型と同様にプログラム内でファンクションブロック型ラベルが使用できる」**
ということになりました。

実はST言語で記述するにしてもファンクションブロックの呼び出しに直接引数を記述しない方がステップ数的に有利だったりするので、引数への代入や引数からの取り出しは呼び出しの外で行うのをデフォルトとしていこうと考えています。


## 過去記事一覧
+ [過去記事一覧](https://qiita.com/fujiteruo/items/af2459d320e8109963db)
Python on Snowflake でよく利用する関数

# Python on Snowflake でよく利用する関数
Python on Snowflake でよく利用する関数を紹介する．

- 使用するウェアハウスを**WAREHOUSE**に指定
```Python
session.use_warehouse("<WAREHOUSE>")
```
- 使用するロールを**ROLE**に指定
```Python
session.use_role("<ROLE>")
```
- 使用するデータベースを**DATABASE**に指定
```Python
session.use_database("<DATABASE>")
```
- 使用するスキーマを**SCHEMA**に指定
```Python
session.use_schema("<SCHEMA>")
```
- **PandasDataFrame**を**TABLE_NAME**に書き込み
```Python
session.write_pandas(<PandasDataFrame>,‘<TABLE_NAME>',overwrite=True)
```
- **PandasDataFrame**をSnowflakeDataFrameに変換
```Python
session.create_dataframe("<PandasDataFrame>")
```
- **SnowflakeDataFrame**をPandasDataFrameに変換
```Python
<SnowflakeDataFrame>.to_pandas()
```
- **SnowflakeDataFram**を**TABLE_NAME**に書き込み
```Python
<SnowflakeDataFrame>.write.mode(“overwrite”).save_as_table("<TABLE_NAME>")
```
- **SQL**の実行
```Python
session.sql("<SQL>")
```
- **SnowflakeDataFrame**を出力画面に出力
```Python
<SnowflakeDataFrame>.show()
```
- **SnowflakeDataFrame**のレコード数を出力
```Python
<SnowflakeDataFrame>.count()
```
- **SnowflakeDataFrame**のカラム名を出力
```Python
<SnowflakeDataFrame>.columns
```
- **SnowflakeDataFrame**のカラム名**COLUMN_NAME**のカラムを抽出
```Python
<SnowflakeDataFrame>.select("<COLUMN_NAME>")
Azure 高速ネットワーク


# はじめに

az-305勉強中に仮想マシンのネットワークパフォーマンス周りを勉強していた際、高速ネットワークについて調べたので投稿します。

https://learn.microsoft.com/ja-jp/azure/virtual-network/accelerated-networking-overview?tabs=redhat


# サポートされている仮想マシン（VM)

windowだと下記がサポート

>Windows Server 2022
Windows Server 2019 Standard/Datacenter
Windows Server 2016 Standard/Datacenter
Windows Server 2012 R2 Standard/Datacenter
Windows 10 バージョン 21H2 以降、Windows 10 Enterprise マルチセッションを含む
Windows 11、Windows 11 Enterprise マルチセッションを含む

VM作成時に「高速ネットワークを有効にする」で「はい」を選択して有効化します。

# シングルルートI/O仮想化

高速ネットワークを使うとシングルルートI/O仮想化（SR-IOV)が可能になります。
名前が長いんですが、これを使うとネットワークパフォーマンスが向上するとのこと。

なんで早くなるかというと「仮想スイッチ上での処理をなくす」ことで通信を早くする仕組みのようです。
仮想スイッチを経由すると色々なポリシーを参照するので遅くなるということですね。

# NIC

高速ネットワークをオンにするとNICが特殊になるみたいです。

下記のブログが参考になりました。

https://qiita.com/maplejava/items/e8b84fb860d09395753b

※NVIDIAの場合はVF インターフェイスというらしいです。
OIDCとは？

# はじめに
OIDCについてメモしておきます。

# OIDCとは
OIDC (OpenID Connect)とは、認証および許可にOAuth 2.0を使用してサービス間でユーザーの同意のもと認証情報を連携するための規格です。

https://www.openid.or.jp/document/

# OIDCの流れ
1. ユーザーがWebサービスやクライアントアプリケーションにログインを試みる
2. WebサービスやクライアントアプリケーションはIDプロバイダーにIDトークン発行を要求
3. IDプロバイダーは要求を受けてトークンを発行
4. ユーザーがトークンを用いてリソースを要求
5. Webサービスやクライアントアプリケーションのリソースをユーザに提供

# おわりに
今回はOIDCの流れを書いてみました。今後GitHubとAWSでOIDCを使うことがあるため、実際に使ってみようと思います。
フロントエンド開発で詰まった時のディグり術５選

こんにちは．フロントエンドエンジニアのavaiceです．

フロントエンド技術は進化が早く，新しいツールやライブラリに触れる機会が多いです．
エラーやよくわからない挙動に当たってしまう事もよくあります．そんな時に私が行っている情報のキャッチアップ術を自分の思考整理も兼ねて記事にしようと思います．

## １．公式ドキュメント

一般的な使用用途であれば，基本的に公式情報を見ればある程度揃います．Q&AやTrouble Shootingのページを用意してくれている事も多いので，私は最初にそこを見るようにしています．

ほとんどのライブラリではアップデートに対応した情報更新も行われているので，バージョン違いで動作しない情報に当たってしまうことも少ないです．

## ２．GitHubのIssue/Discussion（重要）

昔は見ていなかったけれど，見るようになってから解決力が上がった気がします．エラー系の問題であれば，相当変なエラーを引かない限りは同じユーザーがいて解決できます．また，Discussionでは「こういう事やりたいんだけど〜」みたいな議論もよく行われているので，公式ドキュメントにないような実装をしてみたい時に見てみると有益な情報を得られることもあります！

検索するときはIssue/PullRequest/Discussionまで網羅的に調べたい＆Closeした情報も見たいので，最初から入っている`is:pr is:open`などのクエリは消します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730661/2a9c8578-56de-de19-a7c0-214724a53b0d.png)

- 例
    - エラーが出たらGitHub Issueで検索
    - 他の使い方を知りたい場合はDiscussionを確認

## ３．ChatGPTに聞く

私は１，２を見ても解決できなければ，一旦ChatGPTに聞いてみています．というのもChatGPTは多言語に渡ってソースを学習しているので，日本語と英語の情報しか読解できない自分には辿り着けない情報を持っている可能性があるからです．

ただし，情報源は基本的に古いことが多いので，そのままでは使えないケースもあります．あくまで解決の糸口を掴む程度にするのが良いと思います．

基本的に，雑に聞いても答えてくれますが，以下のテンプレートに沿って質問しています．

```plaintext
{エラー全文 or やりたいこと}

上記のようなエラーが出ました．
{技術スタック(r.g. Next.js + Pages Router)}で実装しています．
```

## ４．ネットで検索

上３つで解決できなかったら，ググります．QiitaやZenn，そしてSlackOverflow等に先人の知恵が書き込まれていたらラッキーです．

検索クエリは，普段以下のような感じにしています．

- エラーや不可解な挙動を解決したい
    - エラーメッセージ・コードを全文コピペして検索
        - 意外と出てくる．出てこなかったらちょっとずつ内容を削っていく
- 状況を検索する
    - 「React 再レンダリング 2回呼ばれる」
        - もっと良い検索方法がありそう．知っている方がいたら，コメントで教えてください＞＜


## ５．ソースコードを読む

どうしても解決しない場合は，ソースコードを確認します．
もしここまで到達して解決できたら，記事にまとめておくと誰かが幸せになれると思います．

ソースコードを読むのは難しそうに思えますが，もしフロントエンド系のライブラリであれば普段使っているであろうTypeScriptで書かれている事が多いので，意外と読めます．
（ツールチェーン系はRustやZigなどを使っているケースが多く読むのは難しいですが，意外と どういう挙動なのかはなんとなく理解できることも多いので，一回読んでみると良いと思います．）

### 不可解な挙動を解決したい
不可解な挙動を引き起こしているであろう関数を見つけて，GitHubのリポジトリ内でその関数を検索する．

### そもそも，やりたい事ができる仕様になっているのか知りたい
TypeScriptの型定義（.d.ts）でAPI仕様を確認すると入出力が定義されているので，そこを見ておけば「こういうインプットに対して，こういうアウトプットが欲しい」というのが実現可能かどうかがすぐ分かります．

## 終わりに

個人的にはこの方法で大抵の問題は解決できている印象です．
これでダメだったら別のライブラリを使うか，自分でコントリビュートするしかない事がほとんどなのではないでしょうか．この記事が誰かのお役に立てれば幸いです！
誤情報対策の新境地：RAGを活用したファクトチェックの現実適用と評価

# 現実世界でのファクトチェック: RAGパイプラインの包括的評価とその可能性

今回は、「**Face the Facts! Evaluating RAG-based Fact-checking Pipelines in Realistic Settings**」という論文を紹介します。本研究は、誤情報拡散の深刻な社会問題に対処するため、Retrieval-Augmented Generation（RAG）を活用したファクトチェック手法を提案し、その性能を実証するものです。特に、複雑で現実的なシナリオを対象とした評価が行われており、応用可能性の高い結果が示されています。

---

## 論文情報
- **タイトル**: Face the Facts! Evaluating RAG-based Fact-checking Pipelines in Realistic Settings
- **リンク**: [arXiv:2412.15189v1](https://arxiv.org/abs/2412.15189v1)
- **発表日**: 2024年12月19日
- **著者**: Daniel Russo, Stefano Menini, Jacopo Staiano, Marco Guerini
- **DOI**: 不明

---

## 背景と目的

### 誤情報問題の現状
SNSやオンラインメディアを通じて誤情報が瞬時に拡散する現代、ファクトチェックは社会的に重要な課題です。例えば、COVID-19パンデミック中に広まった誤情報は、ワクチン接種率の低下や不必要なパニックを引き起こしました。また、選挙期間中の誤情報拡散が民主的なプロセスに与える影響も無視できません。

#### 従来の方法論の限界
- **人的リソースの制約**: プロのファクトチェッカーによる検証には時間とコストがかかる。
- **スケーラビリティ不足**: 大量の情報をリアルタイムで処理できない。
- **適応性の欠如**: ソーシャルメディア特有のカジュアルで感情的な表現に対応しきれない。

### 本研究の目的
本研究は、以下の3つの目的を持っています。
1. RAGベースの事実確認パイプラインを現実的な状況で評価する。
2. 主張のスタイルや知識ベースの違いがパイプライン性能に与える影響を明らかにする。
3. 誤情報への迅速で効果的な対処を可能にするアプローチを提案する。

---

## 技術的背景

### RAG（Retrieval-Augmented Generation）とは？
RAGは、大規模言語モデル（LLM）の生成能力を検索技術と組み合わせた手法です。
- **Retrieval（検索）**: 指定された主張に関連する情報を知識ベース（KB）から取得。
- **Generation（生成）**: 検索結果をもとに判定文を生成。

これにより、RAGは既存の知識ベースを活用しつつ、新しい情報への対応力を持つ柔軟なアプローチを実現します。

---

## 実験の概要

### データセット
研究では以下の2つのデータセットが使用されました。
1. **FullFact**:
   - ニュートラルなジャーナリスティックスタイルの主張を含む。
   - 主張と記事の正確なペアリングが特徴。
2. **VerMouth**:
   - ソーシャルメディア風のカジュアルで感情的な主張を収録。
   - 現実のノイズや感情的要素を模倣したデータ。

### 評価指標
- **Hit@1**: 最も関連性の高い結果を検索できた割合。
- **MAP（Mean Average Precision）**: 複数結果における検索精度。
- **ROUGEスコア**: 判定文生成のテキスト一致度。
- **感情一致度**: 主張の感情的トーンに対する生成文の適応性。

### 実験設定
1. **リトリーバーの評価**:
   - 疎型、密型、ハイブリッド、LLMベースの比較。
2. **判定文生成**:
   - Llama-2、Mistralモデルを使用。
   - ゼロショット、ワンショット、ファインチューニングを評価。

---

## 結果と分析

### リトリーバーの性能
- **疎型（Sparse）**:
  - 高速だが感情的なノイズに脆弱。
- **密型（Dense）**:
  - スタイルの変化に対して頑健。
- **ハイブリッド**:
  - 疎型と密型の利点を兼ね備え、コスト効率が良い。
- **LLMベース**:
  - ゴールドKBでHit@1が90%以上の性能を発揮。

### 判定文生成
- **ゼロショット**:
  - 幅広い文脈に対応可能だが、詳細さで劣る場合あり。
- **ワンショット**:
  - 文脈の忠実性と情報量のバランスが優秀。
- **ファインチューニング**:
  - 感情一致度が向上する一方、ROUGEスコアは低下。

---

## 議論と考察

### 他の研究との比較
- 本研究のRAGアプローチは、従来のルールベースシステムに比べて柔軟性が高い。
- 同様のRAGを用いた研究よりも主張スタイルの多様性に対応している点で独自性がある。

### 応用可能性
- **政策立案**: 公共政策における誤情報対策。
- **教育**: デジタルリテラシー教育への応用。
- **企業利用**: ブランドイメージ管理における誤情報監視。

---

## 今後の展望

本研究は、RAGパイプラインの有用性を示したものの、いくつかの課題が残されています。
1. **計算コスト**: 特にLLMベースのリトリーバーは高コスト。
2. **データの偏り**: ゴールドKBに依存するため、現実のデータ不足に対するロバスト性が課題。
3. **多言語対応**: 英語以外の言語への適応が必要。

これらの課題を克服することで、より包括的で実用的なファクトチェックツールの実現が期待されます。

---

この記事が研究者や実務者の皆さまにとって有益であることを願っています。ご意見やご質問はぜひコメント欄でお寄せください。
SAAを取った

# はじめに
今日SAA(AWS Certified Solutions Architect - Associate)を取得しました。
![スクリーンショット 2024-12-21 午後10.39.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546781/c6529906-0f89-3fb0-dacb-74c5383e9a07.png)
タイムリーなのでせっかくならその軌跡をまとめていきたいと思います。

# SAA
## SAAとは
SAAは、コストとパフォーマンスが最適化されたソリューションの設計に重点を置いた資格です。AWSクラウドまたはオンプレミスITでの経験が豊富な受験者にとって理想的な出発点とされています。

試験は130分の時間内に65個の問題（複数選択または複数応答）に回答する形式です。

ネットワークの基礎知識がない方にとっては難しく感じるかもしれませんが、主要な用語を理解していれば十分に取得可能なレベルの資格だと考えています。

## 事前準備
大体勉強時間は3ヶ月くらいで、平日は2時間、休日は合計5時間ほど取って勉強していました。(12月からはAdventCalendarを同時並行でやっていたので平日は0.5~1時間程度の勉強時間になっていた気がします)
やっていたのは以下に示す3つのコンテンツです。

### AWS認定ソリューションアーキテクト-アソシエイト問題集
[Amazonリンク](https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88-%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88%E5%95%8F%E9%A1%8C%E9%9B%86-%E5%B9%B3%E5%B1%B1-%E6%AF%85/dp/486594303X)
これは各サービスの概要を知る基礎固め用のテキストでした。
この本に記載されている問題を解くだけだとちょっと本番とのギャップが大きいので苦戦しそうです。なので教科書的な使い方が向いているのだと思います。

### CloudLicense
[CloudLicenseサイト](https://cloud-license.com/exam/aws-exam2/)
基本的に問題はこちらを最後までずっと繰り返し解いていました。
難易度帯が大体試験と同じくらいで、実際の試験でも同じような問題が出題されます。
模擬試験モードで8割が安定して取れ始めるまで繰り返し解くことをお勧めします。

### AWS Skill Builder
aws公式で提供されている学習プラットフォームです。
ここにはSAAの出題範囲に関する講座や模擬問題等が提供されています。
必須というほどではないですがあると良いのかなと思いました。

# おわりに
この記事ではSAAの試験をとる上でやった勉強等をまとめてみました。資格系の記事は無数に存在しますし語り古されていると思いますが、現時点で上記の勉強方法で受かる人間がいたという証左にでもなれば幸いです。
わかりやすいデータ管理のために！～データ一括管理アプリつくってみた～

# 1.きっかけ #
こんにちは、やまな。です。
小売業で人事のお仕事をしています。

以前は社宅のデータ照合を自動化するためのGASのコードを
ChatPTとともに書いてみました。
よければそちらもご覧ください。

https://qiita.com/yama-na/items/a822eab8155110330284


さて、今回は人事データ管理を一元化すべくAppSheetに挑戦しました！
きっかけは、そう。

**あれ、あのデータどこに保存したっけ！？**

なんてことが起きたからです。

技能実習生は現在3期生から10期生までが働いており、その人数は200人前後。
それなりの人数で情報量もなかなか。
さらに、日本国籍の社員とは違い、ちょっとしたことでも問い合わせがきます。

だからこそ、必要な時に時間をかけずにデータを確認したい！
データの整理もしたい！
という思いから作成に挑むことにしました。

# 2.使用したツール #
[AppSheet](https://cloud.google.com/appsheet?hl=ja)
[ChatGPT](https://chatgpt.com/)
[GAS](https://workspace.google.com/intl/ja/products/apps-script/)

# 3.つくったもの #

![スクリーンショット (209).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888131/69d4ad3d-d4c3-57b2-5299-78cf0bdf9155.png)

文字データの従業員リストに画像データ（PDF）を添付して保存できるようにしました。

![Screenshot_20241210-161216.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888131/3b2ce42f-882b-69e0-cb67-3975687098f5.png)
写真もその場で撮影、登録できるようにしました。（画像はサンプルです）



# 3.制作過程 #
### 基盤をつくる ###
まずは基本情報をGoogleスプレッドに入力します。
サンプルの情報を入力、AppSheetを開いてアプリの基本の形を作りました。
文字情報を中心に項目を作ります。

![コメント 2024-12-21 224206.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888131/c2f1c275-cfac-2ac2-3d74-790e14210ef7.png)

次に表示画面の設定をします。

![コメント 2024-12-21 224407.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888131/4c4f9f29-0211-bcda-5371-63bf9a77040e.png)

Excelで管理していたようにしたかったので基本的には一覧として表示させるようにしました・
スマホでは最初の画面で管理団体を選べるように、また、PCでは左端に管理団体名を表示させて、それぞれの所属の実習生のみ表示できるようグループ化しました。

次に、PDFデータの保存です。

![コメント 2024-12-21 224835.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888131/66082a5f-fe68-c097-b62d-1c48d3801565.png)

この二つはGoogleドライブに保存後、そのリンクを貼り付けることで閲覧可能にしました。

写真は受入で実習生と直接会ったときに写真を撮る可能性も高いので、スマホではその場で撮影してすぐ保存できるようにしています。
もちろん、PCでは写真を撮ることができないので、データを貼り付ける形でもできるようにしています。

### ブラッシュアップ ###
ここからはさらに利便性を高めるための作業に入ります。
社宅の住所の入力が地味に面倒、という声を同僚から頂きましたので、その部分の改善です。

といっても、私は自分でコードが書けない初心者なので、
いつもと同じくChatGPTにお願いして書いてもらいました。

```javascript:スプリクト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888131/b246344a-db00-9ae1-f606-f4f0fa792047.png)
function getAddress(postalCode) {
  if (!postalCode) return '';
  const response = UrlFetchApp.fetch(`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${postalCode}`);
  const data = JSON.parse(response.getContentText());
  if (data.results) {
    const result = data.results[0];
    return `${result.address1} ${result.address2} ${result.address3}`;
  } else {
    return '住所が見つかりません';
  }
}
```
このコードをGASに入力しました。
郵便番号だけ入力すれば、県名と市や区まで入力を自動でしてくれます。


# 4.まとめ #
今回つくりながら職場で使ってもらい、意見・要望を聞いてさらに作りこむ、という作業をしています。
しかしまだまだ発展途上。できていないことも使いこなせていないものもいっぱいです。

特にPDFをリンクで結び付けるのは保存してリンクを取得してさらに貼り付けるという作業が発生しており、簡単にしたつもりで逆に難しくしてしまった部分でもあります。

これからの課題としてはこれです。

:::note warn
・PDFを添付することで自動でGoogleドライブに保存されるようにする
・実際に使いながら問題点を見つけ、改善していく
:::

つくって終わりではなく、継続して使えるものをつくる。
そのために引き続き頑張りたいと思います。
Next.jsから力技でPrisma Studioを開けるようにする

## この記事は何
Prisma Studioをご存知でしょうか？
Prisma StudioとはNodeのORMであるPrismaのデータをUI上で確認できるようにするツールです。

https://www.prisma.io/studio

Prisma Studioを本番環境でも使いたい場合、本来であればアプリケーションサーバーとは分けた環境で用意するのがストレートなアプローチですが、プロダクトの規模やフェーズによってはそれができない場合もあると思います。

この記事ではNext.jsのリバースプロキシの機能を使って、力技でNext.jsと同じアプリケーションサーバー上でPrisma Studioを起動、アクセスできるようにする方法をご紹介します。

:::note warn
この記事で紹介する方法は書いた通り正攻法ではありません。
実際に利用する場合は自己責任でお願いします。
:::


## Next.jsのリバースプロキシとは
Next.jsには`rewrites`という機能があります。

https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites

この機能を使うことで、内部ネットワークの別ポートのアプリケーションなどへプロキシすることが可能です。
詳しくは↓の記事をご覧ください。

https://qiita.com/zksytmkn/items/884a9e97b59ceca846a9

## 方針
方針としては以下のようなシンプルな流れで実装します

- 一つのサーバーでNext.jsとPrisma Studioを立ち上げる
- Next.jsからPrisma Studioにリバースプロキシでリクエストを流す
- Next.jsでPrisma Studioにアクセスする際はBasic認証を行うようにする
    - https://qiita.com/axoloto210/items/747eb784e61b173d30b8


## 実装結果
実装は以下の通りです。
Basic認証に関しては↑の記事の通りなので割愛します。
コードは以下のような前提で実装しています。

- Prisma Studioには`/prisma/admin`でアクセスできるようにする
- package.json内のコマンドの実装には[npm-run-all](https://github.com/mysticatea/npm-run-all)を使用
- Docker内でアプリケーションを立ち上げているため、ネットワークを`0.0.0.0`に指定

```package.json
{
  ...
  "scripts": {
    "start": "run-p start:*",
    "start:next": "next start",
    "start:studio": "prisma studio"
  }
  ...
}
```

```next.config.js
{
  ...
  async rewrites() {
    return [
      {
        source: "/prisma/admin/:path*",
        destination: `http://0.0.0.0:5555/:path*`,
      },
      {
        source: "/prisma/http/:path*",
        destination: `http://0.0.0.0:5555/http/:path*`,
      },
      {
        source: "/prisma/assets/:path*",
        destination: `http://0.0.0.0:5555/assets/:path*`,
      },
      {
        source: "/prisma/index.css",
        destination: `http://0.0.0.0:5555/index.css`,
      },
      {
        source: "/api",
        destination: `http://0.0.0.0:5555/api`,
      },
    ];
  },
  ...
}
```

## はまりポイント
今回力づくでNext.jsからアクセスしているため、ページへのアクセスだけではなく、APIやその他のリソースへのアクセスも全て設定をしてあげる必要があります。
特にこの設定を行うと`/api`というパスがPrisma Studioに占有されてしまうのが少し痛いです。
Prisma Studioのバージョンアップ等により設定する必要のあるパスも変わっていく可能性があるので、動作検証しながら必要な設定を行っていくことを薦めします。
OpenLayersでアニメ―テッドGIF/PNG/WEBPのピンを立てる

### MapLibreアドベントカレンダーから移しました！

すみません、本記事は元々MapLibreアドベントカレンダーに投稿していたものですが、MapLibre対応としては芯を食ってないことに、後の精査でわかりました。
取り急ぎ話題の中心をOpenLayersに変えてFOSS4Gアドベントカレンダーに移し、MapLibreアドベントカレンダー記事としては別のものを今晩中に挙げます（2024/12/25 23:47）。

### Canvas/WebGLベースの地図APIでアニメ―テッド画像のピンを立てる

従来のHTML DOM divベースの地図APIでは、アニメーションGIFやAPNGなどの画像を使用して、簡単にアニメーションマーカーを作成することができました。 しかし、HTML canvasやWebGLを使用する新しい地図APIでは、アニメーション画像を単純にマーカーとして使用することができなくなりました。

筆者は、OpenLayersベースで、古地図やイラスト地図を地図化する[Maplat](https://github.com/code4history/Maplat)というオープンソースプロジェクトを開発していますが、その潜在顧客との要望を交換する中で、民俗イラストマップ、昔ばなしイラストマップなどの中で、たとえば鬼や河童のイラストがアニメーションで動いたりしたら楽しそう、という話をいただきました。
しかし、HTML DOM divベースの地図APIでは簡単に実現できたアニメーションマーカーも、canvasベースのOpenLayersでは実現が難しかったです。
そこで、Canvasベースでもアニメ―テッドGIF/PNG/WEBPの画像を解析して、canvasのコンテキストを定期的に更新してアニメーションマーカーを実現するプロジェクト、[Gyeonghwon](https://github.com/code4history/Gyeonghwon)を開発しました。

### ここから下はたわごとです

元々自分がメインはOpenLayers使いだったので、MapLibreにはあまり触っていなかったのですが、CanvasとWebGLの違いはあれ同じ問題ってあるんじゃないかなと思っていたので、試してみたのが今回でした。
OpenLayersのサンプルを食わせて、これと同じものをMapLibreでできるか？と生成AIに聞いてみたら、ちゃんと動くものを出してきたので、やるやんけさすが生成AI、と喜んで出したのが修正前の記事ですが、公開した後で精査したら、MapLibreのhtml divを使ったマーカー機能で実装されていました。
それやったら、普通にアニメ―テッド画像使えばええ話でした。

というわけで、本ソリューションは今のところOpenLayersのみ対応ということで、MapLibreへの対応は、対応する意味があるかの再検討含めて、課題ということで。

### ~~生成AIの助けを借りて、Maplibreにも対応するよう修正~~

~~Canvasに対応させる仕組みはWebGLにも対応させられると思っていたので、Maplibreでも同じ仕組みが使えるのではないかと思っていましたが、手が回っていませんでした。~~
~~今回、アドベントカレンダーに書くネタとして、Maplibreに対応させてはどうかなと思って、生成AI（Claude 3.5 Sonnet）の助けを借りつつ、Maplibreの対応デモと対応手順を作成しました。~~

* ~~[Maplibreでの利用法](https://github.com/code4history/Gyeonghwon?tab=readme-ov-file#maplibre-gl-js%E3%81%A7%E3%81%AE%E4%BD%BF%E7%94%A8)~~
* ~~[Maplibreでの動作デモ](https://code4history.dev/Gyeonghwon/)~~

~~プロジェクトをモダナイズするのには、３日以上と相応に手間がかかりましたが、Maplibre対応は生成AIにたずねれば、30分で対応できました。~~
~~生成AIすげー。~~

### ~~使えるようなら使ってください~~

~~普段はOpenLayers使いで、Maplibre使いではないので、もしかするとこのようなものを導入しなくてもMaplibreにはアニメ―テッド画像に対応する方法があるかもしれず、その点は詳しくないのですが、~~
~~もし使う意味があるようでしたら使ってください。~~