OmniAICreator/Qiita-1.07M huggingface dataset:
zellij に入門した

# zellij に入門した

皆さんはターミナルマルチプレクサを利用されているでしょうか？
私は時折思い返したように`tmux`を始めてはやめるを繰り返していました。
今回は `zellij` に入門したので記事を書きました。

<!-- zellij の名前の意味  -->
### 名前について

もともとの zellij(ゼリージュ) とはイスラム圏のモザイクタイルによる芸術のことです。
東ローマ帝国のモザイクにインスパイアされたイスラムの職人たちによって、スペイン、北アフリカにまで広められました。
現在ではモロッコが特に有名です。
[Building the Moroccan Court - YouTube](https://www.youtube.com/watch?v=Og6cTlwBTrk)

### 分類

zellij は分類上ターミナルマルチプレクサとして扱われていますが、製作者的にはそれ以上のものとして作っているようです。

```txt
Zellij is a workspace aimed at developers, ops-oriented people and anyone who loves the terminal. At its core, it is a terminal multiplexer (similar to tmux and screen), but this is merely its infrastructure layer.
Zellij has a native layout and plugin system. To understand Zellij a little bit better, let us take a look at the default configuration.
```
[Overview - Zellij User Guide](https://zellij.dev/documentation/overview)

### やりたいこと

- セッション永続化
    - 再起動してもそのまま作業復帰できる
        - 無設定でできる(tmux だとプラグインを使う)
- ペインを分割する
    - 縦横に分割する
    - マウスで移動

## インストール

zellij は Rust 製のプロダクトなので `cargo` でインストールできます。

```shell
rustup update;
cargo install --locked zellij;
```

## zellij の操作

### 主要なコマンド

```shell
USAGE:
    zellij [OPTIONS] [SUBCOMMAND]
```

|項目                            |コマンド                      |
|--------------------------------|------------------------------|
|新しいセッションを名前付きで開く|-s $SESSION_NAME              |
|セッションにアタッチ            |attach [alias a] $SESSION_NAME|
|セッションの一覧                |ls                            |
|セッションをkill                |kill-session [alias k] $SESSION_NAME  |
|全てのセッションをkill          |ka                            |
|セッションをデリート            |delete-session [alias d] $SESSION_NAME |
|全てのセッションをデリート      |da                            |

### 主要なキーバインド

考えてみると,自分の問題は新しいキーバインドを覚えるよりターミナルをもう一枚開いてしまうことでした。
zellij のキーバインドは画面の下部に常に表示されているので覚える必要性が低減されます。

|項目                          |キー               |
|------------------------------|-------------------|
|右にペインを分割する          |\<Ctrl-p\> + n       |
|下にペインを分割する          |\<Ctrl-p\> + d       |
|現在のペインをフローティング化|\<Ctrl-p\> + e       |
|フローティングペインをトグル  |\<Alt-f\>            |
|セッションマネージャーを開く  |\<Ctrl-o\> + w       |
|デタッチ                      |\<Ctrl-o\> + d       |
|リサイズ                      |\<Ctrl-n\> + 矢印キー|

## おわりに

かなりいい感じですが、正直機能的には `tmux` でも問題ないので `zellij` である必要はない気もします。
次はターミナルエミュレータを変えてみようかと思っているので、しばらく使ってみて何かあったら追記します。

## Link

[zellij-org/zellij: A terminal workspace with batteries included](https://github.com/zellij-org/zellij)
[Zellij User Guide](https://zellij.dev/documentation/)
DAppとは何かを初学者にわかりやすく解説

今日は、**DApp (分散型アプリケーション)**について初学者にもわかりやすく解説します。普通のアプリとは何が違い、どういう仕組みで動いているのか。そして実際の例を見ながらビジネスチャンスも考えていきましょう。
※この記事は、ChatGPTの出力を基に作成しています。

---

## 普通のアプリとの違い

### **1. 普通のアプリ**
- FacebookやInstagramのように、普通のアプリは中央集中的なサーバーにデータが保存されます。
- ユーザー情報や投稿データは、その企業のサーバーに保存され、その企業が管理します。

### **2. DApp (分散型アプリ)**
- DAppは **ブロックチェーン上にデータが保存されるアプリケーション**です。
- 中央の管理者がいないため、データは世界中の複数のコンピュータに分散して保存されます。

---

## DAppの仕組みはどうなっているの？

### **1. スマートコントラクトを使用**
- DAppの根幹になるのが **スマートコントラクト** と呼ばれるプログラムです。
- スマートコントラクトは事前に決めた規則に基づき、自動で処理を行います。例えば「一定の条件が満たされたら自動でイベントを実行する」といったプログラムです。

### **2. データはブロックチェーンに保存**
- DAppの主要なデータはブロックチェーン上に記録され、誰でも確認できるため、透明性が高いです。

### **3. ユーザーはウォレットを使う**
- DAppの利用には、**クリプトウォレット**や **Metamask** などのツールが必要です。ユーザーはこれを使ってDAppと相互作用します。

---

## DAppの特徴

| 特徴             | 説明                                                                 |
| ---------------- | -------------------------------------------------------------------- |
| **分散型**       | 特定の企業や組織が管理せず、複数のコンピュータにデータが分散される。   |
| **透明性**       | ブロックチェーン上の記録は誰でも確認できる。                         |
| **改ざんが難しい** | ブロックチェーン上のデータは基本的に変更できない。                   |
| **自動化**       | スマートコントラクトによって自動で取引や処理が行われる。             |

---

## DAppの実際の例

1. **DeFi (分散型金融)**
   - 例: Uniswap (分散型取引所)、Aave (貸し借りプラットフォーム)
   - 金融サービスを仲介者なしで提供し、ユーザー同士が直接取引できる。

2. **ゲーム**
   - 例: Axie Infinity、CryptoKitties
   - プレイヤーがゲーム内アイテムを所有し、それを売買して収益化できる。

3. **NFTマーケットプレイス**
   - 例: OpenSea
   - NFTを購入・売却するためのDApp。

---

## DAppを使うメリット

- **検閲耐性がある**：特定の管理者がいないため、政府や企業による規制を受けにくい。
- **ユーザーが主導権を持つ**：中央管理者がいないため、ユーザー自身が資産やデータを管理できる。
- **透明性と信頼性**：すべての取引やアクションが記録され、誰でも監視可能。

---

## DAppを使うデメリット

- **初期学習コストが高い**：ブロックチェーンやウォレットの知識が必要なため、初学者には難しいことがある。
- **スケーラビリティ問題**：現在のブロックチェーンは大量の取引を処理するのに時間がかかることがある。
- **トランザクション手数料 (Gas代)**：特にEthereum上のDAppでは取引時に手数料が発生することがある。

---

## DAppの仕組みを簡単にたとえると？

> 普通のアプリが「一件の図書館に本を保存している」のに対して、DAppは「世界中の複数の家に同じ本のコピーが保存されている」イメージです。一部が壊れても、他の家の本から情報を復元できるため、システム全体が止まることはありません。

---

## まとめ

DAppは、ブロックチェーン技術を活用し、中央管理者がいないアプリケーションの新しい形です。分散型金融やNFTなど、多様な分野で既に実用化されており、今後もさらなる進化が期待されます。

もし興味を持ったなら、まずは**Metamask**などのウォレットをインストールして、実際にDAppに触れてみると理解が深まるでしょう！
portsのmake configで表示が化ける場合の対処方法

## ports の make configで表示が化ける
14.0R あたりからなのですが、ports のビルド時にデフォルトのオプションから変更したい場合に make configで設定を変更しようとすると locale またはターミナルの環境によっては表示されるダイアログの表示が化けてしまう場合がある様です。

## こんな感じ
![ports_net_rsync_NG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3584428/6a1e2605-f400-fbbe-a33d-abb90571fc97.png)

## 原因
この原因ですが、/usr/ports/Mk/Script/以下にある dialog4ports.sh と思われます。
```sh: dialog4ports.sh から抜粋
# Backwards compat with older version which used stdout [<= 0.1.1] (or stderr [0.1.2]).
# Clear environment of PKGNAME or the dialog will show on older versions
# that do not understand -v.
if ! env -u PKGNAME ${DIALOG4PORTS} -v > /dev/null 2>&1; then
	exec env LC_ALL=C.UTF-8 $DIALOG4PORTS > $OPTIONSFILE 2>&1
fi

# Newer versions use stderr to work around a jail issue
# http://lists.freebsd.org/pipermail/freebsd-ports/2013-March/082383.html
exec env LC_ALL=C.UTF-8 $DIALOG4PORTS 2> $OPTIONSFILE
```

DIALOG4PORTS を呼び出す際に環境変数 LC _ALL を強制的に UTF-8 に設定しているのが原因の様なので, LC_ALL=**_C .UTF-8_** を LC_ALL=**_C_** に変更すると以下の様に正常に表示される様になります。

## 対処後
![ports_net_rsync_OK.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3584428/93d2f9c6-e414-3603-9b87-e045632c8d2a.png)

## おまけ
git log で dialog4ports.sh の 変更履歴を見るとこんな記述が...
```
Date:   Wed Oct 11 09:54:12 2023 +0200

    dialog: force UTF-8 locale

    On some terminal, namely "putty" and "linux", the unicode capability
    are not properly exposed, resulting in a not so nice UI, forcing
    the env to be unicode friendly with executing the DIDALOG commnands
    make the output nice in those environements
```
一部のターミナルで不具合があるので対処したとの事ですが、全てのユーザ環境に対応するのは中々難しいのかもしれません。
ローカルよりもクラウド。クラウドでローカルLLMを動かしてみよう。

# ローカルよりもクラウド。クラウドでローカルLLMを動かしてみよう。
元も子もない記事のタイトルですが、ローカルでLLMを動かすのをクラウドで動かしてみようと思います。

# 前提
- 開発環境
    - MacbookAir 2022 M2
    - メモリ8GB
    - macOS14.4
- 作業
    - Google Cloudのアカウント作成済み
    - gcloudコマンドが利用可能

# クラウドの選定
- Cloud Run + Artifact Registryにしました
→ECS+ECRでもいいんですが、Fargateが高い・・・。

# ライブラリの選定
- Ollama
→簡単にLLM(SLM)のインストールができる。Hugging Faceからも持ってこれたりで便利です。
- Open-WebUI
→ChatGPT風の画面をいい感じに作ってくれる。

上記をすべてコンテナに収めます。お好みでdocker-compose.ymlを書いてみても良いかもしれません。今回は、Cloud Runを使うので、docker-compose.ymlは使いません。

# GCPの設定
- Artifact Registry APIが有効になっていることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/b8783ce8-1c6e-888a-6440-4b9a229a096b.png)

- Artifact Registryにリポジトリを作る
以下２つのリポジトリを作成してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/6f17cad5-b69a-701f-b895-b5bef6ca7ed5.png)

# ローカルの設定
以下のリンクを参照してください。
[GitHub](https://github.com/at-himawari/llm2025_gcp)
一応、簡単に手順を書いておきます。
```bash 
git clone https://github.com/at-himawari/llm2025_gcp.git
```
## backend
Ollamaのイメージを作成します。
```bash
docker build -t phi3:latest .
  
docker tag phi3 asia-northeast1-docker.pkg.dev/プロジェクトID/phi3/phi3:latest
  
docker push asia-northeast1-docker.pkg.dev/プロジェクトID/phi3/phi3:latest
```

## frontend
Open-WebUIのDockerイメージを作成します。
```bash
docker build -t open-webui:latest .

docker tag open-webui:latest asia-northeast1-docker.pkg.dev/プロジェクトID/open-webui/open-webui:latest

docker push asia-northeast1-docker.pkg.dev/プロジェクトID/open-webui/open-webui:latest
```
# Cloud Runの設定
- コンテナをデプロイを選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/bbb76ca4-ce7c-5ed2-6092-9745765506b7.png)

- サービスを選択します
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/7be48583-0086-8c57-277e-d813e32dc390.png)

- 既存のコンテナ イメージから 1 つのリビジョンをデプロイするを選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/ab4ef779-b728-8cbb-1958-d30ac62b9b8a.png)

## 環境変数を設定します
### backend
- Ollamaのイメージを使います。
- backendのエンドポイントURLはfrontendの環境変数OLLAMA_BASE_URLに設定するよ。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/d8abb03d-8e5a-0aa8-0eb1-baa45b00ac75.png)

- コンテナポートを11434に設定するよ。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/56a65d3e-18b5-d1d8-424b-1a60f6a15207.png)


### frontend
Open-WebUIのイメージを使います。
OLLAMA_BASE_URLに、backendのURLを設定します。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596630/51a42af0-7ae4-7865-54cf-30606c377267.png)

無事に作成できましたか？
（結構、端折った）

#接続確認
frontendのエンドポイントURLに接続できたら成功です。~~（イメージがおもすぎて、未確認）~~

2025.2.1追記
phi3:miniで試したところすんなりいきました。
コンテナが落ちるとデータが丸ごと吹っ飛ぶのでお気をつけて
[Vue.js]テキストで数値を入力できるrefを作ろう


input[type="number"]を使うよりtextつかってあげるのが優しいようなので,そんなrefを作りたいと思います

↓参考になりました。ありがとうございます！↓

https://qiita.com/diescake/items/65ce4499ab8a70d029de

https://zenn.dev/funteractiveinc/articles/component-input-number

# こんなかんじ


![2025-01-31 19-20-46.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329559/00e52b3e-3fd8-8171-014a-3eecf9a56750.gif)

全角を半角に変換しさらに関係ない文字を無視してくれるやさしいrefになっています


# 実装

composableにするか迷ったのですが、面白い機能があったので[customRef](https://ja.vuejs.org/api/reactivity-advanced.html#customref
)を使います


・source

このソースは最初のバージョンで、メンテされていないので最新ソースは[追記](https://qiita.com/babu-ch/items/5e3eecf801335ebc3508#%E8%BF%BD%E8%A8%98)から確認おねがいします

```stringNumberRef.ts
import {customRef} from 'vue'

type StringNumberRefOptions = {
  // マイナス許可?
  allowMinus: boolean,
  // 小数点許可?
  allowDecimal: boolean
}

// 全角数値を半角数値にreplaceするやさしいrefです
export function stringNumberRef(
  value: string,
  options: StringNumberRefOptions = {allowDecimal: false, allowMinus: false}
) {
  let internalValue = getValue(value, options);

  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return internalValue
      },
      set(v) {
        internalValue = getValue(v, options)
        trigger()
      }
    }
  })
}

// 変換後の値を返す
function getValue(v: string, options: StringNumberRefOptions) {
  if (v.trim() === "") {
    return ""
  }
  if (isFinite(Number(v))) {
    return v
  }
  const replaced = toHalfWidth(v)
  if (replaced === "-") {
    return replaced
  }
  const allowed = replaced.match(/-?\d+(?:\.\d+)?/)
  if (allowed === null) {
    return ""
  }
  return getNumberText(allowed[0], options)
}

function toHalfWidth(str: string) {
  return str.replace(/[０-９．ー]/g, (c) =>
    c === "ー" ? "-" : String.fromCharCode(c.charCodeAt(0) - 0xFEE0)
  );
}

function getNumberText(stringNumber: string, options: StringNumberRefOptions) {
  let number = parseFloat(stringNumber)
  if (!options.allowMinus) {
    number = Math.abs(number)
  }
  if (!options.allowDecimal) {
    number = Math.trunc(number)
  }
  return `${number}`;
}

```

・使い方
```vue
<script setup lang="ts">
import {stringNumberRef} from "../stringNumberRef.ts";

const text = stringNumberRef("")
const dec = stringNumberRef("", {allowDecimal: true, allowMinus: false})
const min = stringNumberRef("", {allowDecimal: false, allowMinus: true})
const all = stringNumberRef("", {allowDecimal: true, allowMinus: true})
</script>

<template>
  <div>
    <p>整数のみ <input type="text" v-model="text" inputMode="numeric"></p>
    <p>小数点許可 <input type="text" v-model="dec" inputMode="numeric"></p>
    <p>マイナス許可 <input type="text" v-model="min" inputMode="numeric"></p>
    <p>小数点+マイナス許可 <input type="text" v-model="all" inputMode="numeric"></p>
  </div>
</template>
```

# おわり

以外に複雑だったのでgithubにあげてテスト書きたいな

bugはあるかもしれません :sweat: 

# 追記

githubにソースを上げて、テストも書きました
バグ修正などはそちらに入れていきたいと思います

https://github.com/babu-ch/vue-string-number

さらにnpmにも上げてみたので以下コマンドで簡単にインストールしてお試しできます :thumbsup: 

```sh
npm i vue-string-number-ref
```
AssemblyInfo.cs と csproj の変遷：InternalsVisibleTo の記述場所の変化

## 前置き

AIによって生成した記事になります。
個人的な解釈としては「AssemblyInfo.csに書くのもアリ」というAIの結論に対して以下の点から結局 csproj に書くのが安心なのかなぁ、と思っています。

- 公式が csproj に書くことを推奨していることは、そのうち AssemblyInfo.cs を用いたやり方がサポートされなくなってしまうかも？
- ビルドプロセスに適用しやすいということは、CI/CD環境でもトラブルになりにくいのでは？

---
## AssemblyInfo.cs と csproj の変遷：InternalsVisibleTo の記述場所の変化

### 1. 昔のAssemblyInfo.csの時代
.NET Framework や初期の .NET Core では、アセンブリ情報 (`InternalsVisibleTo` を含む) を `AssemblyInfo.cs` に記述するのが一般的でした。

#### 昔の書き方 (AssemblyInfo.cs)
```csharp
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("MyCompany.MyProject.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
```

#### メリット
- 明示的で分かりやすい（アセンブリに関連する情報が `AssemblyInfo.cs` にまとまっている）
- `csproj` をシンプルに保てる
- すぐに編集可能**（手軽に追加・削除しやすい）

#### デメリット
- 手動で作成が必要（`AssemblyInfo.cs` がない場合は作らないといけない）
- アセンブリの情報が複数のファイルに分散しがち
- 自動生成される場合があり、変更しづらいケースがある（.NET Core 以降）

---

### 2. .csproj に書くようになった理由
.NET Core 以降（特に .NET 5+ 以降）では、アセンブリ情報の自動生成が一般化 したため、`AssemblyInfo.cs` に記述しなくても済むようになりました。

#### 現代の書き方 (csproj)
```xml
<ItemGroup>
  <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
    <_Parameter1>MyCompany.MyProject.Tests</_Parameter1>
  </AssemblyAttribute>
  <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
    <_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
  </AssemblyAttribute>
</ItemGroup>
```

#### メリット
- アセンブリ情報を `csproj` に一元化できる
- 追加・削除がビルドプロセスで適用されるため、管理がしやすい
- `AssemblyInfo.cs` が不要になり、コードのクリーンアップが可能
- MSBuild に統合されているため、プロジェクトごとの設定がしやすい

#### デメリット
- 直感的でない（C# コードの中でなく XML に書くのは少し面倒）
- IDE の補完が効かない（`AssemblyInfo.cs` なら `using System.Runtime.CompilerServices;` など補完が効く）

---

### 3. どっちが推奨？
✅ 推奨される書き方
- 新規プロジェクト (.NET Core 以降, .NET 5+) → `csproj` に書く（公式推奨の流れ）
- 既存の `.NET Framework` や `.NET Core` のプロジェクト → `AssemblyInfo.cs` のままでもOK
- 設定が少なく、IDE の補完を活用したい場合 → `AssemblyInfo.cs` に書くのもアリ

公式的には `csproj` に記述する方法が主流になりつつある ものの、
「可読性・メンテナンスしやすさ」の観点では `AssemblyInfo.cs` に書くのも 十分に合理的な選択肢 です。

---

### 4. 結論
「どちらの方法も正解。ただし、プロジェクトやチームの方針による」
- .NET Core 以降では `csproj` に書くのが公式推奨
- 昔ながらの `AssemblyInfo.cs` の方が「C# コードとして管理しやすい」
- どちらを使うかはプロジェクトのポリシー次第
- 「複数の `InternalsVisibleTo` を書く場合、 `AssemblyInfo.cs` の方が直感的」

可読性や変更のしやすさを考えると、`AssemblyInfo.cs` の方が楽な場合も多いので、
`AssemblyInfo.cs` を活用するのも十分アリな選択です。

---
Go 言語の do-while 、あるいはリトライ処理

## golang do-while でぐぐると

C の

``` c:hoge.c
do {
    ループしたい処理
} while (cond);
```

をどう書くのがいいのかなって `golang do-while` でぐぐってみると、だいたい

``` go:hoge.go
for {
    ループしたい処理
    if !cond {
        break
    }
}
```

って書き方が出てきて微妙な気分になるのだが、Go の場合

``` go:hoge.go
for func() bool {
    ループしたい処理
    return cond
}() {
}
```
でもいいんじゃないっすかね。一見しただけでは do-while だと分かりにくいのが玉に瑕。

## リトライ処理

ところで、こういうフローが必要になる場合ってだいたいがリトライ処理なのだが、困ったことにリトライ処理を書く場合には do-while でも微妙に痒いところに手が届かなくて、C でも

``` c:hoge.c
for (;;) {
    ここで複雑な処理
    if (!needRetry) break;
    log("リトライすっぺ");
    awesomesleep(interval);
    interval += interval;  // exponential backoff
}
```

って書くのもなんだしなあと結局

``` c:hoge.c
retry:
    ここで複雑な処理
    if (needRetry) {
        log("リトライすっぺ");
        awesomesleep(interval);
        interval += interval;  // exponential backoff
        goto retry;
    }
```

みたいに goto 使って書いたりするのだが、上の書き方なら

``` go:hoge.go
for func() bool {
    ここで複雑な処理
    if errors.Is(err, tempBusy) {
        return true // リトライするよ
    } else {
        return false // リトライしないよ
    }
}() {
    log("リトライすっぺ")
    awesomesleep(interval)
    interval += interval  // exponential backoff
}
```
という風に書けるし、goto が要らなくなってダイクストラ師もニッコリ。

## 注意点

単なるループとは return や defer の振る舞いが変わる点だけは注意な。もっとも、defer に関しては、ループの中で defer 使うのはだいたいアンチパターンだし、むしろ func で括ることにより「ループが回るたびに毎回 defer が実行されて便利」まであるのでデメリットとも言い難い。return の方はマジ不便な場合もあるので、その時はしょうがないので「無限 for ループを if で break する方」を選ぶなりなんなりしてくらはい。
あとは毎回関数呼び出しされるオーバーヘッドとかあるけど、それが気になる人は Go 使わんでしょ（暴言）。
改めてGolangを理解する② ~ 基本構文から関数までのメモ書き ~

## はじめに
こんにちは！ITスクールRareTECHにてCS（Customer Support）を担当している池村です。今回の記事はGo言語の自分の復習用記事です。一応連続記事ですが、この記事は初心者向けではなく自分用に書いています。

前記事👇

https://qiita.com/ikemura-ren/items/9e3cd3ae30b421efc494

:::note warn
Goから初めてプログラミング言語を触れる人は少ないよなぁ。と思って、ここは軽く流す記事です。
:::


## 基本の振り返り
まずはGoの基本的なHello Worldからです。
```Go:Hello Worldを行う
package main

import "fmt"

func main(){
    fmt.Println("Hello World")
}
```

:::note info
まずは基本的な構文は上記になります。これに追記をしていきます。
:::

#### 変数定義
```Go:変数定義と使用
package main

import "fmt"

func main(){
    name := "Qiita！"
    fmt.Println("Hello", name)
}
```

```Bash:出力してみる
go run main.go

Hello Qiita！
```

#### コメントアウト
コードに反映されないコメントを残すことができる。（どの言語でも）
```Go:コメント
// コメント

/*
コメント
コメントです
*/
```


## 条件分岐
条件分岐はよくいうif文とかですね。さらっといきましょう。

### if文
```Go:if文
x := 2

if x > 0 {
    fmt.Println("プラスです")
} else if x == 0 {
    fmt.Println("0です")
} else {
    fmt.Println("マイナスです")
}

```

:::note info
if文を使うことで、条件に合わせたプログラムを実行できる。実行されるのは{}で囲まれたブロックの中身の処理
:::

### switch文
```Go:switch文
day := "Monday"

switch day {
case "Monday":
    fmt.Println("週のスタートです。憂鬱ですね。")
case "Tuesday":
    fmt.Println("まだ始まって2日目です。頑張りましょう")
case "Wednesday":
    fmt.Println("折り返しです！")
case "Thursday":
    fmt.Println("あと二日でお休みです！")
case "Fryday":
    fmt.Println("金曜日！仕事終わったら天国です！")
default:
    fmt.Println("お休みです")
}
```

:::note info
dayの中身がMondayなので『週のスタートです。憂鬱ですね。』が表示されているはずです。switch文はif-else文の連続をシンプルに書けるため、条件が多い場合に使われることが多い印象です。
:::


## 繰り返し
### for文
```Go:for文による繰り返し
for i := 0; i < 10; i++ {
    fmt.Println(i)
}
```

```Bash:実行結果
0
1
2
3
4
5
6
7
8
9
```

:::note info
iという変数を俗にカウンタ変数と言いますが、この変数を使ってループを行います。
:::

```Go:条件によって色々変えられる
// 2ずつ増やして行ったり
for i := 0; i < 10; i += 2 {
    fmt.Println(i)
}

// 出力結果
0
2
4
6
8

// 減らしていったり
for i := 5; i > 0; i-- {
    fmt.Println(i)
}

// 出力結果
5
4
3
2
1
```

配列とかmap、スライスなどを使って要素を一つずつ取り出すパターンもあります。（というかこちらの方が多い）

```Go:rangeを使うパターン
fruits := []string{"apple", "banana", "cherry"}

for index, value := range fruits {
    fmt.Println(index, value)
}

// 出力結果
0 apple
1 banana
2 cherry
```

:::note info
動的に変わるようなデータの塊を一つずつ取り出すパターンがとても多いです。データベースの値とかはたくさんとってきます。
:::


## 関数
Goの関数についてメモ。
```Go:関数定義と使用
package main

import "fmt"

func main(){
    g := 2
	h := 5

	fmt.Println(add(g, h))
}


func add(g int, h int) int {
    return g + h
}

// 出力結果
7
```

:::note info
add関数は受け取った二つの値を足して、その結果を返しています。
:::

```Go:戻り値二つの場合
package main

import "fmt"

func main(){
    g := 2
	h := 5

	fmt.Println(addAndMultiply(g, h))
}

func addAndMultiply(g int, h int) (int, int) {
    return g + h, g - h
}

// 出力結果
7 -3
```

:::note info
もちろん、変数でそれぞれ受け取ることも可能です。
:::

## おわりに
プログラミングで何ができるかをある程度知っていれば、この辺りは当たり前すぎて面白くないかもしれないです。さらっと自分用の復習のため書いているので、別にこの記事は読む価値ないです。
Pythonのdictとlistは横着しないで定義しろ！


この間コードを書いているときに気がついたときには余りのしょうもなさに自分に呆れ返ったのですが、
Debugで1時間くらい無駄にしたので戒めも込めて記事にします。
ですが、私のようにIaCのためにコード書き始めました！なインフラエンジニアの方には刺さるかもしれません。

## 結局何でハマったのか
いわゆるミュータブルなオブジェクトの生成の際に、ミュータブルなものかイミュータブルなものかを考えていなかったが故のミスです。

例えば、2つFlagを立ててloop内で両方Trueになったらbreakしたい処理がある時に、

`a = b = False`

こんな感じで定義することがあると思います。
これはイミュータブルなオブジェクトのため特に問題になりません。片方を更新した際にもう片方がclearされるわけではないので。

ただし、ミュータブルなものの定義では話が変わります。

`a = b = []`

これだけみたらあーはいはい、となる方は多いと思います。ですがこれの話です。

私は横着者なので、空list2個作りたいしこれでいいや〜で作ってa.appendをしてしまったが故、
bにいらんデータが入ってる…という当たり前の事実に気づかず頭を悩ませました。

```
>>> a = b = []
>>> id(a)
4301621248
>>> id(b)
4301621248
```

このように作ったので当然、以下の通りの状態となります。
```
>>> a.append('YEAHHHHHHH')
>>> a
['YEAHHHHHHH']
>>> b
['YEAHHHHHHH']
```

bにはこんなデータ足した覚えがない、どこでこんなもん足されるんだ！と悩み抜いた後に、
これ定義ダメじゃね？と気がついた次第です。恥ずかしい。

## じゃあどうすれば良いのか

```
>>> a, b = [], []
>>>
>>>
>>> id(a)
4301577344
>>> id(b)
4301621184
```

1行で書きたいならこれでいいし、そもそも横着しないで1行で1つの定義にすべきですね。

他にはdictをcopy()してしまうと同じ事象引きがち。

```
>>> c = {'a': []}
>>> d = c.copy()
>>> c['a'].append(1)
>>> c
{'a': [1]}
>>> d
{'a': [1]}
```

これはdeepcopy()にすることを忘れないようにしたい。
きっと忘れてまたDebugで時間を取られるけど。
ルーレットのEvenOddをウィナーズ投資法でプレイするシミュレーション

![qiita-1280-720.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3998847/fb6a0f5f-b22c-989e-910a-f1f555e210cf.png)

ルーレットでEven（偶数）またはOdd（奇数）に賭ける方法は、赤黒ベットと並んでシンプルで人気のある戦略の一つです。
今回は「ウィナーズ投資法」を利用してルーレットのEven・Oddをプレイし、その結果を検証するプログラムを作成します。

## ウィナーズ投資法とは？

ウィナーズ投資法（Winners Investment Method）は、連敗を活用して賭け金を増減させる戦略です。
特徴的なのは、連敗時に数列を作成し、その数列の法則に従って賭け金を決定する点です。

### ウィナーズ投資法のルール

1. **初期設定**: 最初に1単位（ユニット）を設定（例: 1ドル）
2. **初期ベット**: 最初は1単位を賭ける
3. **2連敗まで継続**: 2連敗するまでは1単位を賭け続ける
4. **数列の作成**: 2連敗した時点で「1・1」の数列を作成
5. **ベット額の決定**: 次のベット額は数列の左端の数字を2倍にした金額とする
6. **ゲームの進行**:
   - 勝った場合: 数列の左端の数字を削除
   - 負けた場合: 前回ベットした単位数を数列の右端に追加
7. **終了条件**: 数列がすべて消えるまで継続

## Pythonでのシミュレーションプログラム

```python
import random

def spin_roulette():
    """ルーレットを回してEven（1）かOdd（0）を返す（0は負け扱い）"""
    outcome = random.randint(0, 37)  # 0から37（0を含む）
    if outcome == 0:
        return -1  # 0は敗北
    return 1 if outcome % 2 == 0 else 0  # Even（1）またはOdd（0）

def winners_investment_simulation(initial_unit=1, max_rounds=100):
    """ウィナーズ投資法でルーレットのEven・Oddをプレイするシミュレーション"""
    balance = 0
    rounds = 0
    numbers = []  # 賭け金の数列
    consecutive_losses = 0  # 連敗カウント
    unit = initial_unit

    while rounds < max_rounds:
        if not numbers:  # 数列が空なら最初の1単位で賭ける
            bet = unit
        else:
            bet = numbers[0] * 2
        
        outcome = spin_roulette()
        
        if outcome == 1:  # 勝ち
            balance += bet
            if numbers:
                numbers.pop(0)  # 数列の左端を削除
            consecutive_losses = 0
        else:  # 負け
            balance -= bet
            consecutive_losses += 1
            numbers.append(bet)  # 負けた金額を数列に追加
            if consecutive_losses == 2 and not numbers:
                numbers = [1, 1]  # 2連敗時に「1・1」の数列を作成
        
        rounds += 1
        print(f"Round {rounds}: Bet {bet}, Outcome {outcome}, Balance {balance}, Numbers {numbers}")
    
    return balance

# シミュレーション実行
final_balance = winners_investment_simulation()
print(f"最終残高: {final_balance}")
```

## シミュレーション結果の考察

このシミュレーションを複数回実行すると、以下のような特徴が見られます。

- 2連敗するまでは1単位の賭けが続くため、大きく負けることは少ない
- 2連敗後に数列が増加すると、負けが続いた場合に賭け金が膨らむリスクもある
- 数列が短縮すれば利益が確定するが、長くなると損失が拡大する可能性もある

ウィナーズ投資法は、一見するとリスクを抑えた戦略のように見えますが、負けが続くと賭け金が大きくなるため、適切な資金管理が求められます。

## まとめ

ウィナーズ投資法を用いたルーレットのEven・Oddベットは、2連敗後の数列管理が鍵となる戦略です。

今後の改良点として、

- 最大ベット額を制限する
- 破産リスクを考慮したシミュレーションを行う
- 実際のカジノのルールに沿った制限を加える

といった点が考えられます。

前回の記事（[モンテカルロ法のシミュレーション](https://qiita.com/cl3x/items/5f108540b842d0f11324)）と合わせて、ぜひ参考にしてみてください！
ReactのuseActionStateフックを理解する

Reactの`useActionState`フックは、フォームの状態を管理するための高度なツールであり、動的なフォーム送信を効率的に処理できます。React 19で利用可能になり、JavaScriptバンドルが完全に読み込まれる前でもフォームをインタラクティブにすることができます。特に、React Server Components（RSC）と組み合わせることで、応答時間を最適化し、ユーザーエクスペリエンスを向上させる強力なツールです。

この記事では、`useActionState`フックの概要を説明し、従来のフォーム送信方法をどのように改善できるかを実際のコードを使って紹介します。

## useActionStateとは？

`useActionState`フックを使用すると、フォームのアクションの結果に基づいてコンポーネントの状態を更新できます。これにより、フォーム送信をより柔軟に制御でき、動的な状態管理が可能になります。

### フックの構文

```tsx
const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);
```

- `fn`: フォーム送信時に呼び出される関数。前の状態とフォームデータを引数として受け取ります。
- `initialState`: フォームアクションが実行される前の初期状態。
- `permalink`（オプション）: フォームが変更するURL。動的なコンテンツがあるページに便利です。
- `state`: 現在のフォームの状態。
- `formAction`: フォームの`action`または`formAction`プロパティに渡す新しいアクション。
- `isPending`: アクションが進行中であるかを示すブール値。

## useStateとuseRefを使った従来のフォーム送信

`useActionState`を使用する前に、まず`useState`と`useRef`を使ってフォーム送信をどのように処理するかを見てみましょう。

```tsx
import { useState, useRef, RefObject } from "react";

function FeedbackForm() {
  const [feedback, setFeedback] = useState("");
  const formRef: RefObject<HTMLFormElement | null> = useRef(null);

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(formRef.current || undefined);
    const message = formData.get("feedback");

    // サーバー遅延のシミュレーション
    await new Promise((resolve) => setTimeout(resolve, 1000));

    setFeedback(`受信: ${message}`);
  }

  return (
    <form ref={formRef} onSubmit={handleSubmit}>
      <textarea name="feedback" placeholder="フィードバックを入力" />
      <button type="submit">送信</button>
      <p>{feedback}</p>
    </form>
  );
}
```

## useActionStateを使った改善

次に、`useActionState`を使用して、フォームをよりインタラクティブにし、サーバーアクションを活用する方法を紹介します。

```tsx
import { useActionState } from "react";

async function submitFeedback(prevState: unknown, formData: FormData) {
  const message = formData.get("feedback");
  await new Promise((resolve) => setTimeout(resolve, 1000)); // サーバー遅延のシミュレーション
  return `受信: ${message}`;
}

function FeedbackForm() {
  const [feedback, formAction, isPending] = useActionState(submitFeedback, "");

  return (
    <form action={formAction}>
      <textarea name="feedback" placeholder="フィードバックを入力" />
      <button type="submit">送信</button>
      {isPending && <p>送信中...</p>}
      {!isPending && <p>{feedback}</p>}
    </form>
  );
}
```

### 主な改善点

- **簡潔な状態管理**: `useActionState`により、`useState`を使わずにフォーム状態を動的に管理。
- **自動フォーム処理**: フォームの送信処理を自動化し、イベントリスナーの設定が不要に。
- **保留状態の管理**: `isPending`フラグを使用して、フォーム送信中の状態を示すことでUXを向上。

## まとめ

Reactの`useActionState`フックは、フォームアクションの結果に基づいて状態を管理できる便利なツールです。従来のフォーム送信方法から`useActionState`に移行することで、コードを簡潔にし、インタラクティブ性とユーザーエクスペリエンスを向上させることができます。

`useActionState`を活用することで、応答性が高くメンテナンスしやすいフォームを作成できます。特に大規模なアプリケーションでは、頻繁なフォームのやり取りを効率的に処理できる点が大きなメリットです。
2025年版 実際のSAP P_C4H34_2411試験問題

SAP P_C4H34_2411認定試験の準備は、挑戦的な努力になることがありますが、Passitcertify実際の問題セットを活用することで、準備を大いに強化できます。Passitcertifyは、実際の試験形式と難易度に合わせた、最新かつ正確なSAP P_C4H34_2411試験問題を提供しており、試験で予想される内容を現実的にプレビューできます。これらの問題に取り組むことで、さらに学習が必要な分野を特定でき、準備戦略を最適化できます。多くの受験者が、Passitcertifyの資料で試験の内容の大部分がカバーされていたと報告しており、初回で成功を収めています。学習スタイルやスケジュールに最適な方法で学習できるように、PDF、デスクトップ練習ソフトウェア、ウェブベースの練習テストという3つの柔軟な形式で学習資料が提供されています。Passitcertifyの実際の問題を学習計画に取り入れることで、SAP P_C4H34_2411試験に自信を持って取り組み、認定を取得することができます。

特別オファー：

35％割引: SAP P_C4H34_2411の問題と練習試験ソフトウェア全てに特別35％割引をご利用いただけます。
90日間の更新: 購入日から90日間、無料で最新の学習資料が更新されます。
2025年版SAP P_C4H34_2411試験問題をダウンロード: https://www.passitcertify.com/sap/p-c4h34-2411-questions.html

PassitCertify SAP P_C4H34_2411試験キーワード2025：

P_C4H34_2411問題 | P_C4H34_2411試験問題 | P_C4H34_2411問題PDF | 無料P_C4H34_2411問題 | P_C4H34_2411練習問題 | P_C4H34_2411実際の問題 | P_C4H34_2411PDF問題 | 実際のP_C4H34_2411問題 | 公式P_C4H34_2411問題 | 有効なP_C4H34_2411問題 | 検証済みP_C4H34_2411問題 | 最新のP_C4H34_2411問題 | 更新済みP_C4H34_2411問題 | 本物のP_C4H34_2411問題 | 実際のP_C4H34_2411問題 | P_C4H34_2411ダンプ | P_C4H34_2411実際の問題 | P_C4H34_2411ダンプPDF | 無料P_C4H34_2411実際の問題 | P_C4H34_2411練習ダンプ | P_C4H34_2411実際の問題 | P_C4H34_2411PDFダンプ | 実際のP_C4H34_2411ダンプ | 公式P_C4H34_2411実際の問題 | 有効なP_C4H34_2411ダンプ | 検証済みP_C4H34_2411実際の問題 | 最新のP_C4H34_2411ダンプ | 更新済みP_C4H34_2411ダンプ | 本物のP_C4H34_2411実際の問題 | 実際のP_C4H34_2411ダンプ
loglotateが使えなかったため、shellscriptとcrontabによってログローテーションを実装

## ログローテーションとは
ログファイルが一定のファイルサイズに達したり、一定の期間が経過したら、ファイル名を変更してログファイルを切り分け、古くなったログファイルは消去する作業を言います。これによって、ログファイルの肥大化を防ぎます。

## logrotate(ログローテート)とは
ログファイルをローテーションし、必要に応じて圧縮などを行うツールです。多くのLinuxディストリビューションで採用されています。

「logrotate」は、デーモンではなく「cron」によって実行されます。このため、logrotateの利用にはcronが動作していることが必須となります。もっとも、たいていの場合cronはデフォルトで動作しているはずです。また、logrotateの設定ファイルを変更したとしても、サービスの再起動は必要ありません。

## logrotateの仕様
/etc/logrotate.confでログローテーション全体の設定ができ、
各サービスごとの設定をしたい場合は、/etc/logrotate.d配下に設定ファイルを作成することで利用することができます。

※詳細は以下記事が分かりやすかったです
https://qiita.com/shotets/items/e13e1d1739eaea7b1ff9


## 今回やりたかったこと
毎日出力されるアプリケーションログにおいて、3日経過したものをローテーションして削除したかった。
また、今回は圧縮も行わない設定としたかった。
最初は、logrotateを使用してログ削除を行いたかったのですが、ここで問題が発生。

```/etc/logrotate.conf
daily          # ログを毎日ローテーション
rotate 3       # ローテーションを 3 回分保持
missingok      # ログファイルがなくてもエラーを出さない
notifempty     # ログが空の場合はローテーションしない
```


例として、Applog_20250101.logをローテーションする場合、

１日目：
Applog_20250101.log　（出力日）

２日目：
Applog_20250101.log_1
Applog_20250101.log

３日目：
Applog_20250101.log_2
Applog_20250101.log_1
Applog_20250101.log

４日目：
Applog_20250101.log_3
Applog_20250101.log_2
Applog_20250101.log_1
Applog_20250101.log

４日目：
~~Applog_20250101.log_4~~ (ログは削除される)
Applog_20250101.log_3
Applog_20250101.log_2
Applog_20250101.log_1
Applog_20250101.log

のような状況になりました。

アプリログが毎日出るとすると、その数分だけ**ファイル数が増えていく**という状況に…
これでは本末転倒だ!となり、他の方法を考えることになりました。

## shellscriptとcrontabを使用したログローテーション
結果として実施した方法は、３日間経過したログファイルを削除するというロジックのshellscriptを実装し、crontabで設定した日時でそのシェルを実行し、ローテーションを行うという方法です。

shellscriptは下記のような実装を行いました。
```delete.sh
#!/bin/bash

# 削除対象のディレクトリを指定（例: /path/to/directory）
TARGET_DIR="/path/to/directory"

# 3日以上前に更新されたファイルを検索して削除
find "$TARGET_DIR" -type f -mtime +3 -exec rm -f {} \;

# 終了メッセージ
echo "3日以上更新されていないファイルを削除しました。"
```


このシェルをcrontabによって、毎日午前9時に実行する場合、下記のような設定となります。
1.crontab の編集
ターミナルで crontab を編集するために、次のコマンドを実行します：
```
crontab -e
```
これにより、現在のユーザーの crontab ファイルが開かれます。
今回はroot権限で設定しました。


2.スケジュールの追加
crontab の編集画面に、毎日午前 9 時にスクリプトを実行するための行を追加します:
```
0 9 * * * temp/delete.sh
```
crontabについては、以下記事が分かりやすかったです。
https://qiita.com/nemutas/items/3f5816eabbf0eda5e6a9

## まとめ
今回は、実現したかったことがlogrotateではうまく実装ができなかったため、shellscriptとcrontabを使用したログローテーションを実装しました。
条件によっては、logrotateを上手く活用することもできますので、なにかのご参考になると幸いです。
PCの電源を入れる前に接続しないと外部ディスプレイが検出されない

## はじめに

新しく支給されたノートPCが外部ディスプレイに接続できないという相談があった。

マシン: dynabook G83/M
OS：Windows11

ノートPCの電源を入れる前に外部ディスプレイをHDMIコードで繋げている場合は外部ディスプレイに接続できるが、ノートPCの電源を入れた後に外部ディスプレイをHDMIコードで繋げても、ディスプレイが検出されないという現象が発生していた。

無事、解決したので、備忘録として残しておく。

## 解決した方法
デバイスマネージャーでディスプレイアダプターを確認した所、「Microsoft基本ディスプレイアダプター」となっていた。

以下、URLの記事によると、「Microsoft基本ディスプレイアダプター」が問題で、これを適切なドライバにすればよいと分かった。

https://qiita.com/sshojiro/items/f0b77b37acc7a537f170


このノートPCの仕様を確認したところ、グラフィックアクセラレーターには「インテル® UHD グラフィックス 620（CPUに内蔵）」とあった。


https://dynabook.com/business-mobile-notebook-g-series/g83m-jan-2019-13-3-inch/pg83mmjxh37ad21.html


そのため、以下URLの「インテル® ドライバー & サポート・アシスタント」をインストールし、ドライバーを更新したところ、無事、ディスプレイアダプターが「Intel UHD Graphics 620」となり、外部ディスプレイも検出されるようになった。

https://www.intel.co.jp/content/www/jp/ja/support/detect.html
OpenAIのユーザーに対する姿勢に不安を感じた話

:::note warn
ChatGPT以外の対話型AIサービスを契約したことが無い点ご了承ください。
:::
:::note warn
メールアドレスの件はGeminiとClaudeも当てはまります
:::

## きっかけ
ChatGPT便利ですよね。すでに無くてはならない存在になりつつあります。
そんなChatGPTですが、この度アカウントを**無警告で**削除されました。
幸い異議申し立てにより復旧できたのですが、アカウントを丁寧に扱おうとしないOpenAIの姿勢に不安を感じました。
<img width="500" alt="サポートから送られてきたメール" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795435/0f922c93-f132-95b4-0c6c-cfa328850cb5.jpeg">

## 不安1：ユーザー対応
異議申し立ての際、一度も経過報告の返信がありませんでした。
政府発行の個人情報資料を提出したのですが機械的な受け付け連絡すら無く、「本当に対応してくれているのか」「誤ったところに提出していたらどうしよう」などの不安にさいなまれました。

数日かかると記載ありましたが、一週間以上音沙汰が無く経過報告を求めるメールを何度か送るも無視され続け、時間だけが過ぎていきました。
仕方が無いので再度現状報告しつつ異議申し立てを行うと、完全に同じ提出案内メールが再度届き、提出するとわずか1日程度で復旧されました。（提出案内メールが来るには2日かかりましたが）

一度目はやはり対応されていなかったのでしょう。
もしも一定時間たつと抹消されるシステムであるならば恐ろしいです。

サブスクは解約され、差額は返金されませんでした。
Pro更新した直後とかだと悲しすぎます。


## 不安2：問題あるアカウントは捨てさせるスタンス
メールアドレス（と電話番号）を変更できないことはご存じでしょうか。
変更するには再度まっさらなアカウントで始めることになります。
会社のメールアドレスで登録された方は退職の際は諦めてください。

メールアドレスが乗っ取られた場合に備え、OTP（ワンタイムパスワード）を有効にしておきましょう。
[Enabling Multi-Factor Authentication (MFA) with OpenAI](https://help.openai.com/en/articles/7967234-enabling-multi-factor-authentication-mfa-with-openai "OTP有効化方法")
[「Google Authenticator」をApp Storeで](https://apps.apple.com/jp/app/google-authenticator/id388497605 "OTP発行アプリ")
[Google 認証システム - Google Play のアプリ](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=ja&pli=1 "OTP発行アプリ")

ちなみに、[OpenAI Platform](https://platform.openai.com/account/members "OpenAI Platformのメンバー管理ページ")からメンバーを追加してという案内がヘルプページにありますが、追加した子アカウントでログインしても親アカウントのチャット内容などを見ることはできませんでした。
あくまでもOpenAI Platformの一員になっただけで親アカウントに乗り移ることはできないようです。

## ChatGPT使い続けて大丈夫？
今後、更にパーソナライズされてパートナーのような存在になっていくと予想します。
しかしそのパートナーは問題発生時に消滅しやすい設計であり、ユーザー対応も雑であることは否めません。
その時になって困っても遅いので、代替やローカルLLMを検討しつつあります。
ユーザー学習データ標準フォーマットみたいなのができたら、ローカルのフロントを介して生成AIサービスを使うというやり方が安全なのでしょうかね。

これまでインフラ的なサービスでトラブルが起きたことが無かったので、向き合い方の重要性に気付かされた良い経験でした。
CloudFront Logging v2 で S3 に保存する場合、バケット名に制約がある

# はじめに

2024年11月に CloudFront のアクセスログ出力機能が v2 に改善された。

https://dev.classmethod.jp/articles/cloudfront-access-log-update-202411/

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/standard-logging.html

この新しい機能を使うことで、ログファイルの出力をデフォルトで年月日などのレベルでパーティショニングができるため、ログファイルの検索やAthenaなどの機能を利用しようとするときに非常に便利になる。

そこでこの機能を利用するために S3 への保存を選んだのだが、以下のようなエラーが発生してしまう。

![SnapCrab_NoName_2025-1-31_18-44-50_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502582/ae9217fe-d464-9d05-9fa3-ba17de68bf0d.png)

> 1 validation error detected: Value '**********************************' at 'name' failed to satisfy constraint: Member must satisfy regular expression pattern: [\w-]*

ここでは、この問題の解消法についてをまとめる。

# 結論

エラーメッセージの `name` が何のことかがわからなかったが、これはバケット名である。

問題を解消するには、正規表現 `[/w-]*` に一致する、つまり、**アルファベット (a-zA-Z), アンダースコア (_)、半角整数 (0-9) およびハイフンのみの名前で作成された S3 バケットを指定する必要がある** ようだ。

バケット命名規則では `.` を含むことができる（実際、今回テストに指定したバケット名は `www.t-kigi.net` であり `.` を含んだバケット名である）が、これを含むと指定の正規表現に一致しないため注意する必要がある。

https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html?icmpid=docs_amazons3_console

なお、この機能が登場するまでの S3 への保存機能（レガシー）ではバケット名に `.` があってもログ保存ができる。 
そのため、将来的にはこの制限はもしかするとバグとして解消されるかもしれない。
コンテキストの違い

### はじめに
コミュニケーションの話です m9(^Д^)

チャットコミュニケーションにおいて、「話がうまく伝わらない」「意図と異なる解釈をされた」などが起きることがあると思います。
その原因の一つとして、「コンテキスト（背景情報）」の違いがあるかと思います。
人によって持っている前提情報や解釈の仕方が異なるため、同じ言葉でも異なる意味に受け取られることがあります。

特に、日本語では主語や修飾語が省略されやすいため、相手のコンテキストを考慮しないと誤解が生じやすくなります。
※開発の人間としては、特に、営業と開発間は特に生じやすい気がします。
　

### チャットやビジネスコミュニケーションでの課題
近年、SlackやTeamsなどのチャットツールがビジネスコミュニケーションの主流になっています。
しかし、これらのツールでは対面での会話と異なり、主語や修飾語が省略されがちになるため、コンテキストの違いによる誤解が生じやすくなります。

1. **「誰が」「何を」したのか不明確になる**
   - 例：「終わりました！」 → 何が、どこまで終わったのか分からない
   - 例：「修正しました！」 → どの部分を修正したのか不明
　
2. **指示の解釈に時間がかかる**
   - 例：「これお願いします！」 → 「これ」が何を指しているのか分からず、確認が必要
   - 例：「やっときます！」 → 誰が何を、いつまでにやるのかが曖昧
　
3. **タスク管理が曖昧になる**
   - 例：「対応しました」 → 何を対応したのか
   - 例：「やる予定です」 → いつまでに、誰がやるのか不明確
　
4. **修飾語の省略による混乱**
   - 例：「大きいファイルを送ります。」 → 「大きい」の基準が人によって異なり、誤解を招く可能性がある
   - 例：「早めに対応します。」 → 「早め」が具体的にいつなのかが分からず、期待値がずれる。今日中なのか、明日までなのか。

　※そういえば、今日中とは、明日の午前5時までを指す。と昔いた会社の先輩に教わったことがあります。ハードワーク。

### コンテキストの違いによる具体的な齟齬の例
#### **例文1（コンテキストの違いによる誤解）**
**「資料を更新しました。」**

**問題点:**
- どの資料を更新したのか不明。
- 更新内容が相手の期待と異なる可能性がある。

**こうしたほうが良い**
- 「最新の営業報告書を更新しました。主に〜ページのグラフを追加しました。」
- 「会議資料のスライドを更新しました。レイアウトを調整しました。」

#### **例文2（修飾語の違いによるズレ）**
**「なるはやでお願いします。」**

**問題点:**
- 「なるはや」の基準が人によって違う。
- どれぐらい急ぐべきかが分からない。

**こうしたほうが良い:**
- 「今日の17時までに対応をお願いします。」
- 「明日の午前中までに完了するようお願いします。」

#### **例文3（タスク範囲の認識ズレ）**
**「修正お願いします。」**

**問題点:**
- どの部分を修正するのか不明。
- 誰が修正するのか分からない。

**こうしたほうが良い:**
- 「ホームページのトップページデザインを修正してください。画像のサイズを統一してください。」
- 「昨日のバグリストにあるエラーAを、開発チームが修正してください。」

### コンテキストの違いによる齟齬を防ぐ方法
1. **前提情報を明確にする**
   - 例：「今回のプロジェクトでは〇〇の基準で評価します。」
   - 例：「会議で話した件ですが、〇〇についての対応をお願いします。」
　
2. **主語や対象を明確にする**
   - 例：「私が明日のプレゼン資料を作成します。」
   - 例：「営業部の田中さんが〇〇の確認を担当します。」
　
3. **修飾語を具体化する**
   - 例：「なるべく早く」→「今日の15時までに」
   - 例：「大きいファイル」→「20MB以上のファイル」
　
4. **コンテキストを補足する**
   - 例：「この修正は〇〇という背景があるため、△△の方針で対応します。」
   - 例：「先ほどの話ですが、A案のほうが適していると思います。」
　
### おわりに
やっていることが違ったりするのだから、コンテキストがずれるのは当たり前。
人が理解できるような、思いやりのあるコミュニケーションを心がけたいものです。

新人の頃に「主語がない」と100万回ぐらい言われていた事を思い出しました。
[Python] 特定の警告だけを無視したい（VSCode）

Pythonでコードを書いているとき、**特定の警告を無視したい…** って感じるときありませんか？

たとえば、こんな時とか…
```py
import re

qwe123rty = "qwe123rty"

num = re.search(r"(\d+)", qwe123rty)[0]
```
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652113/cbb26294-9a34-9c8b-a43a-86c3bcafbc60.png)
文字列の中に数字が含まれてるのは明らかなんだし、ただうるさいだけです。

これだけのために`None`チェックをするのは大げさですし…。
```py
found = re.search(r"(\d+)", qwe123rty)
if found:
    num = found[0]
else:
    raise Exception("どうせ例外出すんだから結局同じこと")
```
```py
found = re.search(r"(\d+)", qwe123rty)
assert found is not None  # 多少短く書ける
num = found[0]
```
（文字列に手を加える可能性があるなど、丁寧に`None`チェックをした方が良い場合もあります）


# 環境
- Python 3.11.9
- VSCode 1.96.4
  - Pylance 2024.12.1

普通の環境です。VSCodeでPythonを使うなら通常はPylanceでしょう。


# `# type: ignore` ではダメ
`# type: ignore` を突っ込めば赤波線を問答無用で非表示にすることはできますが…
これでは、関係ない警告も巻き添えで非表示にしてしまいます。
```py
import re

qwe123rty = "qwe123rty"

num1 = re.search(r"(\d+)", qwe123rty)[0]  # type: ignore
num2 = re.search(r"(\d+)", str(1 / None)())[0]  # type: ignore
#                          ^^^^^^^^^^^^^^^ エラーの塊
```
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652113/4ee6debc-2f74-9955-f936-175c4480390a.png)

あきらかにエラー詰め合わせなのに警告が消えてる！
これは大問題です。1行とはいえ、とても危険です。

`# type: ignore` では細かいフィルタリングなどはできないため、別の方法でignoreをする必要があります。


# `# pyright: ignore[～～]` を使う
`# pyright: ignore[～～]` の記法でignoreすることで、**特定の警告のみを無視する** ことが可能になります。

～～ の中身は、VSCodeのホバー表示や問題ペインで確認できる `Pylance(reportOptionalSubscript)` の文字列を入れます。
```py
import re

qwe123rty = "qwe123rty"

num1 = re.search(r"(\d+)", qwe123rty)[0]  # pyright: ignore[reportOptionalSubscript]
num2 = re.search(r"(\d+)", str(1 / None)())[0]  # pyright: ignore[reportOptionalSubscript]
#                          ^^^^^^^^^^^^^^^ エラーの塊
```
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652113/c813c1f1-00d2-8427-42aa-28c869a551a1.png)

`re.search`だけエラーが消えていることが確認できます。
消したかった「"None" 型のオブジェクトは添字可能ではありません」の警告のみが消えていて、ほかの警告は残っていることも確認できます。

これで、鬱陶しい警告だけを非表示にすることができる…！！


# 注意点：Pyrightのみです
見るからにそんな感じがしますが、Pyrightによる型チェックが働いている環境でしか効きません。
（Pylanceは内部でPyrightを使っています）

mypyでこれをやりたい場合は、以下のようにするそうです。
（環境によっては`--enable-error-code`の指定が必要とのこと）
```py
# 'foo' is defined in 'foolib', even though mypy can't see the
# definition.
from foolib import foo  # type: ignore[attr-defined]
```
https://mypy.readthedocs.io/en/stable/error_codes.html

`# type: ignore`の後にエラーコードを追加するんだそうな。
直感的でいいですね！

もちろんPyrightとエラーコードは共有していないので、mypyに対応する場合はPyrightを捨てる必要があります。
`# type: ignore` で全部まとめて捨てるよりかはマシでしょう。


# まとめ
`# type: ignore` は危険
【kintone認定 カスタマイズスペシャリスト】合格体験記

## はじめに
先日、kintone認定 カスタマイズスペシャリストに無事合格できたので、資格についてと学習方法について紹介します:ok_woman_tone1::dizzy:

## kintone認定 カスタマイズスペシャリストとは
kintone API、User API、cybozu.comの仕様や設定について基本的な知識を持ち、プログラミングを用いたkintone開発のスキルがあることを証明するものです。
受験資格は、 [kintone認定アソシエイト](https://cybozu.co.jp/kintone-certification/level/associate/?_gl=1*1thafq*_ga*MTE4MzA2MjEwNS4xNzIwMDUyMzg4*_ga_M1R7LYZ6DW*MTczODMxNTYwNS4xLjAuMTczODMxNTYwNS42MC4wLjA.*_gcl_au*MTcwMzIzOTAwOS4xNzM4MzE1NjA0*_ga_T5K95WXL54*MTczODMxNTYwNS42LjAuMTczODMxNTYwNS42MC4wLjA.)に合格していることです。

[kintoneの詳細はこちら](https://kintone.cybozu.co.jp/)
[kintone認定 カスタマイズスペシャリストの詳細はこちら](https://cybozu.co.jp/kintone-certification/level/customization-specialist/)

## 学習方法
### ①ノートにまとめる
この資格はテキストの問題集が無く、[kintone認定資格 カスタマイズスペシャリスト学習ガイド](https://cybozu.dev/ja/kintone/miscellaneous/kintone-certification-customize-specialist-guide/)を基に勉強する必要があります。
読むだけでは頭に入らないので、自分なりにノートにまとめました。試験ではかなり細かい部分まで出題されるので、ここは出ないであろうと自分で出題範囲を限定してしまわないようにしましょう。

### ②テスト勉強用アプリ [暗記メーカー](https://ankimaker.com/ja)の活用
問題を解かないと自分の理解度が分かりづらいので、暗記メーカーに自分で考えた問題を作成しました。これを何回も繰り返すことで頭の中にインプットしていきます。

### ③学習サイト [kintone カスタマイズ勉強会 - devCamp](https://page.cybozu.co.jp/-/devcamp)の活用
これについては受験の日に偶然見つけたのですが、試験のサンプル問題集です。今見つけるのかと悔しさもありましたが、本番に近い問題なので解いておくと良いと思います。
最後まで動画を見ると無料のバウチャーがもらえます！（先着順だったので、もう無いかもしれないですが）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700107/9d929c53-342d-7c09-be65-f10eef076d3e.png)

### 試験を受けてみて
結果は合格ラインのぎりぎりの60%でした:worried:
試験前には自信がありましたが、実際に受けてみると細かい部分まで出題されており、まだ理解しきれていない分野があることに気づきました。時間をかけてしっかりまんべんなく理解してからの受験をおすすめします！

## さいごに
合格まで時間が掛かりましたが、無事に合格できてよかったです:blush:
「SQLアンチパターン」の気づき（クエリ3）

## はじめに

こんにちは。小川です。
以前から気になっていた「SQLアンチパターン」という本を読みました。
とても良い本で今まで気づかずにやっていたことがSQLアンチパターンなんだと知ることができました。
勉強になったので、学んだことを言語化して量が多いのでいくつかの記事に分けて紹介していこうと思います。
今回は第Ⅲ部のクエリのアンチパターンについて記載します。
この記事は[「SQLアンチパターン」の気づき（クエリ2）](https://qiita.com/pesysyon/items/d003f88686ac93f57880)の続きになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/edfcea05-fe0b-f2b8-c4c9-0881241eae1e.png)

## 17章.スパゲッティクエリ

#### アンチパターン：複雑な問題をワンステップで解決しようとする
SQLは非常に表現力に優れた言語で、1つのクエリで全てのタスクを処理することもできます。
だからと言って、SQLは一つのクエリで全てを解決することを強制しませんし、ときにはそれが良くないアイデアである場合もあります。

#### デメリット
1つのクエリですべてを処理しようとすると以下の問題があります。
- デカルト積が生じてしまうことがある
  - 2つのテーブルがあった場合、それらのテーブルから総当たりとなる集合をデカルト積と呼びます
  - デカルト積は2つのテーブルの関係を定義しない場合、つまりWHERE句やJOIN句での結合の失敗時に発生しやすい
  - 1つのクエリで全てを処理しようとする試みは、複数のテーブルの関係が曖昧になり、意図しない結合に発展しやすい
- クエリの記述や修正、デバックが難しくなる

#### 解決策：分割統治を行う
- ワンステップずつ
  - 意図しないデカルト積が生じているテーブル間に論理的な結合条件が見つからない場合、単に条件がそもそも存在しない可能性もある。デカルト積を避けるには、幾つかのクエリに分割する必要がある
- UNIONを用いる
  - 複数のクエリの結果は、UNIONによって一つの結果セットにまとめることができる
  - 各サブクエリの結果を合わせたものが、クエリの結果として出力される
  - UNIONは、両方のサブクエリの列に互換性があるときにのみ使用できる
- CASE式とSUM関数を組み合わせる
  - 条件ごとの集約を一つのクエリでシンプルに行うために、CASE式とSUM関数を組み合わせる方法がよく使われる
- SQLを用いたSQLの自動的な記述
  - 複雑なSQLクエリを分割すると、データの値によってわずかに異なる、似たようなクエリをいくつも作成することがある
  - コード生成 (コンパイルや実行が可能なコードをコードから出力する技法) を用いれば、そういった繰り返しを避けることができる

## 18章.インプリシットカラム（暗黙の列）

#### アンチパターン
インプリシットカラムとは、暗黙的な列指定を不適切に使用したために問題が発生するアンチパターンです。

プログラマーが入力を手間だと感じる例の1つが、SQLクエリですべての列名を指定することです。
```sql
SELECT bug_id, date_reported, summary, description, resolution,
  reported_by, assigned_to, verified_by, status, priority, hours
FROM Bugs;
```
ワイルドカード(*)を使うとクエリを簡潔に書くことができます。
```sql
SELECT *
FROM Bugs;
```
また、INSERT文を書く際も、列を明示的に指定せずに省略できます。
```sql
-- Before
INSERT INTO Accounts (account_id, account_name, first_name, last_name, email,
  password_hash, portrait_image, hourly_rate) VALUES (DEFAULT,
  'bkarwin', 'Bill', 'Karwin', 'bill@example.com', SHA2('xyzzy', 256), NULL, 49.95);

-- After
INSERT INTO Accounts VALUES (DEFAULT,
  'bkarwin', 'Bill', 'Karwin', 'bill@example.com', SHA2('xyzzy', 256), NULL, 49.95);
```

しかし、ワイルドカードや暗黙的な列の指定には様々な問題があります。

#### 問題
- リファクタリングにおける問題
  - 先ほどのBugsテーブルにdate_dueカラムを追加します
  ```sql
  ALTER TABLE Bugs ADD COLUMN date_due DATE;
  ```
  - そうすると、VALUESの列数が一致しないためINSERTでエラーを返すようになります
- 隠れた代償
  - ワイルドカードはパフォーマンスにも悪影響を及ぼします

#### 解決策：列名を明示的に指定する
ワイルドカードを使わず、明示的に列を書きましょう。
```sql
SELECT bug_id, date_reported, summary, description, resolution,
  reported_by, assigned_to, verified_by, status, priority, hours
FROM Bugs;

INSERT INTO Accounts (account_name, first_name, last_name, email,
  password_hash, portrait_image, hourly_rate)
VALUES ('bkarwin', 'Bill', 'Karwin', 'bill@example.com',
  SHA2('xyzzy', 256), NULL, 49.95);
```

## まとめ
今回は第Ⅲ部のクエリのアンチパターンについて一部まとめてみました。
この記事はこの本を読んで、私がこういう理解をしましたということを言語化してみました。
とても勉強になる本なので皆様もぜひ読んでみてください。

以上、小川でした。
ElastiCacheでRedisからValkeyに変更してみた

こんにちは、サーバエンジニアの池脇です。
今回はElastiCacheで新たにサポートされたValkeyにエンジン変更を行ったので手順等を紹介したいと思います。

## Valkeyとは
https://valkey.io/

ValkeyとはインメモリデータベースのOSSです。
今までインメモリデータベースとしてよく利用されていたのはRedisでしたが、7.4からライセンスの変更が行われた[^1]ためElastiCacheでは利用できなくなり、新たにValkeyをサポートすることが発表されました。
Redisをフォークしたインメモリデータベースであるため、コードやアーキテクチャの変更を行うことなくValkeyに乗り換えることが可能です。[^2]


## Valkeyに乗り換えるメリット
1番大きいのは**費用が安くなる**ことです。
サーバレスでは **33%**、ノードベースでも **20%** のコストカットができるとのこと。(詳しい料金については[こちら](https://aws.amazon.com/jp/elasticache/pricing/)を参照)
他にも
- コードやアーキテクチャの変更が不要
- ダウンタイムなしでの移行が可能

という点も移行に対する障壁が少ないという意味でポイントです。
またAWSがValkeyプロジェクトを支援しているため、今後のことを考えても積極的にValkeyに乗り換えていくべきでしょう。
詳しくは下記のブログをご覧ください。

https://aws.amazon.com/jp/blogs/news/get-started-with-amazon-elasticache-for-valkey/

## 実際にやってみる
では実際にValkeyへの変更をやってみましょう。
AWSコンソールから「ElastiCache」にアクセスし「Redis OSS キャッシュ」から変更を行いたいキャッシュ名を選択。
下記の画像のように変更を選択。
![スクリーンショット 2025-01-31 17.31.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/56b8fdac-b562-b1ef-2cee-c21bdf263bd2.png)
「クラスター設定」の「モード」で**Redis → Valkey**に変更。
![スクリーンショット 2025-01-31 17.34.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/cb586a7c-57c5-96ec-4554-3cfe042c540f.png)
下記画像のように「エンジンバージョン」、「パラメータグループ」が表示されるので問題なければそのまま下までスクロールし「変更をプレビュー」を選択。
![スクリーンショット 2025-01-31 17.34.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/5d892a04-c3ca-376d-d10a-48c32ac50372.png)
プレビューを確認して問題なければ「すぐに適用」のチェックをつけたまま変更を選択。
![スクリーンショット 2025-01-31 17.34.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/6c0f3970-0c18-5a3a-1d55-1ddd8df5ffee.png)
下記画像のようにステータスが「Modifying」になっていれば作業は終了です。
![スクリーンショット 2025-01-31 18.01.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/cc27111c-ffbe-3686-313a-5a012975d5ca.png)
今回試した環境では15分ほど待つと「Redis OSS キャッシュ」から「Valkey キャッシュ」に移動し、ステータスが「Available」になりました。
移行中にキャッシュを利用しているサービスを触ってみましたが、エラーは発生しませんでした。また移行後にValkeyの中を確認してみましたが、キャッシュしている内容に欠落等がなかったためサービス影響なく移行できたようです。

## まとめ
ElastiCacheでのRedisからValkeyへの移行はとても簡単な上にダウンタイムがなく、サービス影響なしで実行できました。
特に費用面でValkeyに変更することによって受けられるメリットが大きいので、まだRedisを利用しているのであればぜひ移行を検討してみてください！

## 参考
- [ElastiCacheでValkeyがサポートされたけど何が良いのか検証してみた](https://ca-srg.dev/6d99a5ff263346cbaebec589ee744db1)
- [Amazon ElastiCache for Valkey を試した](https://www.seeds-std.co.jp/blog/creators/amazon-elasticache-for-valkey/)
- [Amazon ElastiCache for RedisからAmazon ElastiCache for Valkeyに変更してみた](https://dev.classmethod.jp/articles/amazon-elasticache-for-redis-amazon-elasticache-for-valkey/)

[^1]: [Redis7.4からのライセンス変更について](https://zenn.dev/ktny/articles/9ccd18cd19c26d)
[^2]: 現時点での[最新バージョンの8.0系](https://github.com/valkey-io/valkey/releases/tag/8.0.0)でもRedis7.2.4との互換性がある
AWS S3にアップロードした画像ファイルをブラウザで表示する

AWSのS3に、自前のコードにて画像(png)ファイルをアップロード。その後、画像ファイルをブラウザにて表示しようとしたところ、画像ファイルがダウンロードされる挙動となってしまいました。

その際の解決方法を自分の備忘として残しておきます。
本来ならば実機で確認すべきなんですが、環境を用意する時間がなかったので、文章のみで記載します。（未来の自分へゴメンナサイ。。）

### 原因
原因としては、画像ファイルのアップロードの際に使用するputObjectで「Content-Type」を明示的に指定していないためでした。

S3へのアップロードを行う際にContent-Typeを確認してみると、「application/octet-stream」が指定されていました。

これは、バイナリデータを意味しており、特定のMIMEタイプが定義されていない場合や、サーバーがコンテンツの種類を認識できない場合に使用される汎用的なMIMEタイプです。

S3へのアップロード時にContent-Typeを指定していない場合、「application/octet-stream」が既定で設定されるかは探しきれませんでしたが、Content-Typeが「application/octet-stream」になる場合、ブラウザはデフォルトでファイルのダウンロードを行うようです。

### 対策
対策としては、putObjectにContent-Typeを明示的に指定することです。

今回、ブラウザに表示させたいのは画像(png)ファイルだったので、Content-Typeに「image/png」を指定することで、ブラウザ上の別タブで画像ファイルが表示されます。


以上
背景除去アリーナを作って、最高のモデルをベンチマークしてみた！ 皆さん、こんにちは！


チャットボットアリーナに触発されて、様々な背景除去アルゴリズムをベンチマークし、特に難しいシチュエーション、例えば髪の毛、毛皮、そして透明なオブジェクトに対して最高のものを探すための背景除去アリーナを構築しました。  想像してみてください。ふわふわの毛、そして扱いにくい透明なオブジェクト… 多くのツールが苦労するような、まさに厄介なケースです。

そこで、皆さんのテストのご協力をお願いしたいのです！このアリーナでは、同じ難しい画像セットに対して、様々なアルゴリズムを試すことができます。特に、以下の点についてフィードバックをいただけると嬉しいです。

精度: 各アルゴリズムは、髪の毛、毛皮、透明なオブジェクトをどれほど上手く処理できるでしょうか？それぞれのカテゴリで明確な勝者はいますか？
一貫性: あるアルゴリズムは様々な画像で優れたパフォーマンスを発揮するでしょうか、それとも一貫性がないでしょうか？
使いやすさ: 比較プロセス自体は、分かりやすく、理解しやすいでしょうか？
ご協力いただける方は、こちらからアリーナにアクセスできます: 
https://huggingface.co/spaces/bgsys/background-removal-arena

皆さんのフィードバックは、どの背景除去アルゴリズムが最も優れているかを判断する上で非常に重要です！大小に関わらず、どんな意見でも大歓迎です。どうぞよろしくお願いいたします！
NewRelicでログデータをcurlで投入する

## はじめに
NewRelicでログ監視のアラートポリシーを作る際に、ポリシーの妥当性を確認するためログデータを生成したくなった。

ドキュメントを見たが正直わかりづらいので手順をメモしておく。
https://docs.newrelic.com/jp/docs/logs/log-api/introduction-log-api/

## インジェスト用の license_key を用意する
まず躓いたのがここ。
ネットの記事などから`Key type`を`User`で作成していたが、正しくは`Ingest - License`のキーを使用する。
（ドキュメントにはちゃんとライセンスとは書いてあった）

## POST用のjsonデータを用意する
ここはかなり柔軟性があるらしく、割と適当でもOK。
今回は次のようなファイルを用意した。

```
{
  "entity.name": "sample.entity",
  "level": "ERROR",
  "message": "alert policy test data.",
  "newrelic.source": "logs.APM"
}
```

なお実際に投入された際のデータは下記の通り。timestampは自動で入るので入れなくてOK。
```
{
  "entity.name": "sample.entity",
  "level": "ERROR",
  "message": "alert policy test data.",
  "newrelic.logPattern": "nr.DID_NOT_MATCH",
  "newrelic.source": "api.logs",
  "timestamp": 1738315035641
}
```

## curlで投入する
冒頭のLicenseキーを用意
```
$ export INGEST_LICENSE=XXXXXXXXXXXXXXXXXXXXXXXXXXXX   
```

`https://log-api.newrelic.com/log/v1` へ作成したjsonをPOSTする。（この際の宛先URLはリージョンによるらしい）
```
$ curl -X POST https://log-api.newrelic.com/log/v1 \ 
-H 'Content-Type: application/json' \ 
-H "Api-Key: $INGEST_LICENSE" -d @payload.json 
```

次のようにrequestIdが返されれば成功。`{}`の場合は失敗しているので要確認。
```
{"requestId":"5b6f7dff-0001-bc09-2ee5-0194bba673f9"}
```
VSCode が勝手に Python の仮装環境を起動する


```
  "python.terminal.activateEnvironment": false,
```

を `settings.json` に追加すると、勝手に VSCode が Python の仮装環境を起動するのを阻止できる。

[Python environments in VS Code](https://code.visualstudio.com/docs/python/environments) によると、Python 仮装環境は次のように決まるらしい。

* ワークスペースに `.venv` があると自動的に仮装環境が選ばれる。
* Python 仮装環境から code コマンドで VSCode を起動すると自動的にその仮装環境が選ばれる。
* その他の場合は仮装環境は選ばれない。

しかし！勝手に前回の仮装環境が選ばれるなど勝手な事が起こる。そのような場合は明示的に使いたい環境から改めて code コマンドで VSCode を起動するか上記のように activateEnvironment を false にすると良い。

一年くらい悩んでいたのでここに記す。
PowerShellスクリプトの文字コード

## 日本語を含むPowerShellスクリプトの文字コード
推奨されている「UTF-8 with BOM」を設定します。
なお、私の環境ではデフォルトで設定された「UTF-8」では文字化けしました。

> 主に Windows アプリケーションと Windows PowerShell を使用する場合は、BOM または UTF-16 を使用した UTF-8 などのエンコードを使用することをお勧めします。
複数のプラットフォームで作業する場合は、BOM で UTF-8 を使用することをお勧めします。

https://learn.microsoft.com/ja-jp/powershell/scripting/dev-cross-plat/vscode/understanding-file-encoding?view=powershell-5.1#choosing-the-right-encoding


## 設定方法
ファイルを保存する際に、以下のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191704/0709ad47-a457-3980-96bf-60d67cae1e11.png)