OmniAICreator/Qiita-1.07M huggingface dataset:
【ChatGPT＋Code Interpreter】で画像の吹き出しに日本語を入れます。


　どうも、カーブミラーです。

　今回は、画像の吹き出しに日本語を入れます

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::

　まずは、ニュースです。

　画像生成AIの
　　NijiJourneyのアニメスタイルに
　　　パーソナライゼーション機能が
　　　　追加されました。
　[Midjourney公式ポスト](https://x.com/midjourney/status/1831875002016395597?t=NaChFVIW8xLDHAn6zZzWBA&s=19)

　ようは、
　　固定のキャラを
　　　何度でも描ける、って機能です。
　　　　たぶん（←使わないから😅）

　X-Twitter界隈では
　　“すごい（本当だ）”というよろこびと
　　　“全然ダメ”という言葉が
　　　　見受けられていますね。
***
　さて、本題です。

　今回は、
　　画像の吹き出しに
　　　日本語を入れます。

　DALL-E3では
　　吹き出しに英語は
　　　入れられます。
　　　　（崩れたりしますけど）

　でも日本語は
　　入れられず、
　　　やろうとしても
　　　　ハングルっぽいとか
　　　　　漢字？みたいなものに
　　　　　　なってしまいます。

　そこで
　　Code Interpreterで
　　　入れてやればいいのでは？と
　　　　考えたわけです。

　画像の上に
　　文章を重ねることは
　　　以前にやりましたね。
[【ChatGPT＋Code Interpreter】で画像にテキストを書き込みます。](https://qiita.com/kabumira/items/22d1501db9da458ae7c8)

　ですが
　　吹き出しに
　　　文章を重ねるには
　　　　その位置を指定しなければ
　　　　　なりません。

　何かのツールを
　　使えば、座標や範囲を
　　　得られはしますが、
　　　　Code Interpreterに
　　　　　そのデータを手入力するのは
　　　　　　手間ですよね。

　そこで
　　昨日（2024/09/06）の記事の内容を
　　　使うわけです。
[【ChatGPT＋Code Interpreter】で画像内の吹き出しを認識して、赤枠で囲みます。](https://qiita.com/kabumira/items/0ccd8c1e40b77d98ab7a)

　昨日の記事により、
　　位置と範囲がわかります。

　あとは、その中に
　　文章を重ねるだけです。
***
　では、はじめましょう。

　ここでは
　　昨日の元画像を
　　　使います。

　また、日本語を使うので
　　その点の注意も必要です。
　　　ようはフォントをアップロードが
　　　　必要だということです。

　今回は
　　元画像とともにフォントも
　　　アップロードしますが、
　　　　これは別々でも構いません。

　　その際は、
　　　フォント、元画像の順で
　　　　お願いします。

　手順は
　❶GPT-4oであることを確認
　❷日本語フォントと元画像を
　　　アップロード
　❸Prompt入力
```Text:
・今後、CodeInterpreterではこのフォントを使用してください。

・OpenCVを使用して、画像内の白い領域を検出し、その領域を輪郭として抽出してください。その後、検出された白い領域の中から最も大きい矩形を特定し、その矩形の中に、“好き”と描画してください。
・ダウンロードリンクを示してください。
```
　❹送信
　❺ダウンロードリンクが表示

　得られた画像が
　　こちらです。
![1725679335858.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/40f485d3-fa94-99db-31e3-b043f50967f4.jpeg)

　ごらんのように
　　Promptでは位置も範囲も
　　　指定していません。

　ここまで長かった😭

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
【よくある】next.jsでtailwindが効かない

# はじめに
個人開発を始めようと思い、next.jsとtailwindで実装を試みました。

ですが、tailwindが効かない。。。

なぜだと思い、google先生に聞いたところ
同じところでハマっている先人たちが多いこと多いこと。

ですが、先人たちの教訓とは別のところで効いていなかったので記事を書きます。

# next.jsにtailwindを導入する

### Tailwindと必要なパッケージをインストール
```bash
npm install -D tailwindcss postcss autoprefixer
```

:::note info
しっかりとこの三つをインストールしましょうね
:::

### Tailwindの設定ファイルを生成
これにより`tailwind.config.js`と`postcss.config.js`が生成されます。
```bash
npx tailwindcss init -p
```

### Tailwind の設定を編集
contentオプションにプロジェクトのpagesやcomponentsディレクトリを指定します。
これにより、これらのディレクトリ内のファイルにTailwindのスタイルが適用されるようになります。
```js
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```
:::note warn
このcontentの適応範囲が実際とあっていなくて反映しない場合も多いみたいですよ
:::

### グローバル CSS に Tailwind を適用
`styles/globals.css`にTailwindの基本スタイルをインポートします。
以下のコードをglobals.cssに追加します。
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### _app.js の設定
Next.jsでは、_app.jsファイルでグローバルなCSSをインポートする必要があります。

```js:pages/_app.js:
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default MyApp;
```
:::note warn
自分はこの_app.jsの設定ができていなくて失敗していました！
:::

# 最後に
色んな先人たちが失敗してますが、以外に自分と全く同じ失敗を見つけるのは難しいですね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3369754/c270a9d5-35c2-17bd-d159-19234699e241.png" width=50%>
Salesforce組織のディスク情報をApexを実行して確認する

## 記事を読んで得られること
ディスクの使用量を確認するのに設定画面からポチポチやらなくて済む

## 実装
[OrgLimit クラス](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_class_System_OrgLimit.htm)を使う

```
public with sharing class StorageUsage {
    Map<String, System.OrgLimit> limitsMap = OrgLimits.getMap();
    System.OrgLimit dataStorageLimit = limitsMap.get('DataStorageMB');
    System.OrgLimit fileStorageLimit = limitsMap.get('FileStorageMB');

    public Integer getDataValue() {
        return dataStorageLimit.getValue();
    }

    public Integer getDataLimit() {
        return dataStorageLimit.getLimit();
    }

    public Integer getFileValue() {
        return fileStorageLimit.getValue();
    }

    public Integer getFileLimit() {

        return fileStorageLimit.getLimit();
    }
}

```

## 実行方法
以下をデバックで実行
```
StorageUsage su = new StorageUsage();
System.debug('Usage Data Value:' + su.getDataValue());
System.debug('Maximum Data Limit:' + su.getDataLimit());
System.debug('Usage File Value:' + su.getFileValue());
System.debug('Maximum File Limit:' + su.getFileLimit());
```

## 結果
Integerなので小数点以下が出ないのが痛し痒し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/0e2827ee-f141-053f-3b1e-396cf23c4cfb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542419/0e3ff719-ea1d-3757-2a0d-e99e001381a9.png)

## 使いどころ
* バッチに組み込んで自動化する（週次や月次で実行して結果をメールやChatterへ通知）
    * 半年くらい経過を見ることでストレージ枯渇のタイミングが見えてくる
* 容量が気になったタイミングでデバッグ実行する

以下コピペでデバッグ実行したら動く
```
Map<String, System.OrgLimit> limitsMap = OrgLimits.getMap();
System.OrgLimit dataStorageLimit = limitsMap.get('DataStorageMB');
System.OrgLimit fileStorageLimit = limitsMap.get('FileStorageMB');

StorageUsage su = new StorageUsage();
System.debug('Usage Data Value:' + su.getDataValue());
System.debug('Maximum Data Limit:' + su.getDataLimit());
System.debug('Usage File Value:' + su.getFileValue());
System.debug('Maximum File Limit:' + su.getFileLimit());
```
qiita cliのテスト


# Qiita CLIを使ってQiitaに投稿する

- publicフォルダ配下に記事を配置

## 各種コマンド

**ブレウザでプレビュー**

```
npx qiita preview
```

**記事の作成**

```
npx qiita new 記事のファイルのベース名
```

**記事の投稿**

```
npx qiita publish 記事のファイルのベース名
```

**全ての記事の反映**

```
npx qiita publish --all
```
【JavaGold】例外とアサーション

# 例外とアサーション

### マルチキャッチ
* ExceptionとRuntimeExceptionをマルチキャッチで同時に扱うことはできない。

プログラマーが独自に作成する例外クラスは、java.lang.Exceptionクラスのサブクラスでなければならない。

```java:マルチキャッチ実装例①
try {
    // do something
} catch (AException | BException b) {
    // do something
}
```

```java:マルチキャッチ実装例②:SampleExceptionクラス
public class SampleException extends Exception {
    public SampleException(String message) {
        super(message);
    }
}
```
```java:TestExceptionクラス
public class TestException extends SampleException {
    public TestException(String message) {
        super(message);
    }
}
```
```java:Sampleクラス
public class Sample {
    private static void test() throws TestException {
        try {
            // do something
            throw new TestException("A");
        } catch (SampleException | RuntimeException e) {
            throw new RuntimeException("B");
        }
    }

    public static void main(String[] args) {
        try {
            test();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
```
```:実行結果
B
```

### try-with-resources
* try-with-resourcesの主な目的は例外処理ではない。
* try-with-resources文で自動的に閉じられるリソースを定義することができるのは、java.io.Closeableインタフェースとjava.lang.AutoCloseableインタフェースのいずれかを実装したクラス
* リソースはfinalもしくは実質的にfinalではなくてはならない。
* try-with-resourcesを使って記述するとリソースが自動的に閉じるのに伴い、finallyブロックが必要なくなった。
* 複数のリソースを対象とする場合は、セミコロン「;」で区切って列挙する。
* try-with-resourcesのtryブロック内で例外が発生したとき、close、catchブロック、finallyブロックの順番で実行される。
* AutoCloseableを実装し、closeメソッドをオーバーライドする。

```java:構文
try (自動的に閉じるリソース宣言) {
    // リソースを使った処理
}
```

```java:実装例
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileCopy {
    public static void main(String[] args) {
        try (BufferedReader in = new BufferedReader(new FileReader(new
                                        File("input.txt")));
                BufferedWriter out = 
                    new BufferedWriter(new FileWriter(new
                        File("result.txt")));) {

            String line = null;
            // データをコピーする
            while ((line = in.readLine()) != null) {
                out.append(line);
                out.newLine();
            }
            out.flush();
        } catch (IOException e) {
            throw new RUntimeException(e);
        }
    }
}
```

* closeメソッドのほうでも例外が発生している場合は、catchされるのは、tryブロック内で発生したException。

```java:実装例
public class TroubleResource implements AutoCloseable {
    @Override 
    public void close() throws Exception {
        throw new RuntimeException("trouble");
    }
}

public class TroubleMaker {
    public static void main(String[] args) {
        try (TroubleResource a = new TroubleResource()) {
            throw new Exception();
        } catch (RuntimeException e) {
            System.out.println("A");
        } catch (Exception e) {
            System.out.println("B");
        }
    }
}
```

```:実行結果
B
```

引数がnullでないことを確認するためのアサーション
```
assert param != null;
```

アサーションを有効にするためのコマンド
```
java -ea Sample
```
特定ディレクトリしたのエクセルファイル全体で検索したい時のメモ

# このドキュメントどこにあるの？

データ仕様とかがエクセルで定義されている場合があるんですがGrepでは難しいですよね。
もちろん、excelファイル自体はzipなので解凍してXMLをgrepすれば…できなくはないのですが整形済みで結果を見たいですので今回はやめておきました。
また、VBA使ってマクロでできるのですが、マクロ形式の拡張子のファイル作ったり結構面倒くさいのでこの方法も却下です。
ということで、いつものコマンドからサクッと検索できる方が良いと思うので作ってみました。

## ソースコード

```requirements.txt
openpyxl
pandas
```

```grep_excel.py
import os
import pandas as pd
from openpyxl import load_workbook
import sys


def grep_excel(folder_path, search_word):
    """
    指定ディレクトリの以下のEXCELファイルを再帰的に検索する
    :param folder_path: 検索するディレクトリパス
    :param search_word: 検索ワード
    """
    # 検索結果を保存するリスト
    results = []

    # フォルダ内のすべてのファイルを再帰的に走査
    for root, dirs, files in os.walk(folder_path):
        for file_name in files:
            # ~$で始まるファイルを除外
            if (file_name.endswith(".xlsx") or file_name.endswith(".xlsm")) and not file_name.startswith("~$"):
                file_path = os.path.join(root, file_name)

                # Excelファイルを開く
                wb = load_workbook(file_path, data_only=True)

                # すべてのシートをループ
                for sheet_name in wb.sheetnames:
                    sheet = wb[sheet_name]

                    # シート内のすべてのセルをループ
                    for row in sheet.iter_rows():
                        for cell in row:
                            if cell.value and search_word.lower() in str(cell.value).lower():
                                # 検索ワードが見つかった場合、結果をリストに追加
                                results.append({
                                    'ファイル名': file_name,
                                    'シート名': sheet_name,
                                    'セルアドレス': cell.coordinate,
                                    'セルの内容': cell.value,
                                    'ファイルパス': file_path  # ファイルパスも結果に追加
                                })

    # 検索結果をDataFrameに変換
    df = pd.DataFrame(results)

    # 結果を表示
    if not df.empty:
        print(df)
    else:
        print("指定したワードが含まれるセルは見つかりませんでした。")

    return df


if __name__ == "__main__":
    # コマンドライン引数から検索対象のフォルダと検索ワードを取得
    if len(sys.argv) != 3:
        print("使用方法: python grep_excel.py <フォルダパス> <検索ワード>")
        sys.exit(1)

    # 検索処理の実行
    result_df = grep_excel(sys.argv[1], sys.argv[2])

    # 結果をExcelに出力する場合
    output_path = '検索結果.xlsx'
    result_df.to_excel(output_path, index=False)
    print(f"検索結果が {output_path} に保存されました。")
```

## 使い方

### ライブラリのインストール

```
pip install -r requirements.txt
```

### 実行

```shell
python grep_excel.py path/to/excel_dir 検索したいワード
```
10/3に『Javaエンジニアのためのソフトウェアテスト実践入門』を出版します（＋同内容Udemyコースのお知らせ）

### 自己紹介

皆さん、こんにちは、Udemy講師の斉藤賢哉です。私はこれまで、25年以上に渡って企業システムの開発に携わってきました。特にアーキテクトとして、ミッションクリティカルなシステムの技術設計や、Javaフレームワーク開発などの豊富な経験を有しています。様々なセミナーでの登壇や雑誌への技術記事寄稿の実績があり、また[「アプリケーションアーキテクチャ設計パターン」](https://amzn.asia/d/9avaCyF)といった書籍も執筆しています。

### ソフトウェアテストに関する書籍を出版します

今般、技術評論社様から『Javaエンジニアのためのソフトウェアテスト実践入門』～自動化と生成AIによるモダンなテスト技法～を出版することとなりました。発売日は10/3ですが、Amazonでは先行予約が開始されています。
https://www.amazon.co.jp/dp/4297144352

表紙は最終調整中ですが、こんな風になる見込みです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597954/8ed7559c-3a4b-e545-185a-742aee6621aa.png)

この書籍は、ソフトウェアテストの基本的な考え方から始まり、JUnit 5を中心としたJavaベースの様々なテスティングフレームワークの利用方法を詳細に解説します。
- **JUnit**：xUnitテスティングフレームワーク
- **Mockito**：モッキングフレームワーク
- **DBUnit**：DBテスト効率化のためのJUnit拡張ライブラリ
- **Spring Boot Test**：Spring BootのためのJUnit拡張ライブラリ
- **RestAssured**：RESTサービスのためのテストライブラリ
- **WireMock**：モックHTTPサーバー作成ライブラリ
- **Selenium**（**Selenide**）：WebブラウザのUIテスト自動化フレームワーク
- **Gatling**：負荷テストフレームワーク

主にJavaエンジニア向けですが、ソフトウェアテストの考え方や技法は、言語を問わずに参考にしてもらえると思います。
またAppendix（補足）として、**GitHub ActionsによるCI/CDパイプラインの構築方法**や、**Chat GPTを活用したテスト効率化手法**についても取り上げます。

### 書籍と同内容のUdemyコース『Javaテスト基礎＆実践』リリースのお知らせ

上記書籍と同内容のUdemyコース「現役アーキテクトが教える『Javaテスト基礎＆実践』」を先日リリースしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597954/924d0152-812b-4bca-dd2a-be521e59f218.png)

ちょうど昨年、ウィーンの美術史美術館でブリューゲルの『バベルの塔』を見てきたこともあり、ソフトウェアテストのイメージにも合うので、全体のモチーフとして使っています。

このUdemyコースの内容は、上記書籍とほとんど同じです。
そしてコースの「売り」の一つが、開発環境全部入りの仮想マシンがOracle VM VirtualBoxの仮想マシンとして提供されるという点です。本コースの開発環境は、仮想マシンとしてUbuntu（22.04 LTS）上に構築されています。この仮想マシンをVirtualBox上で動作させると、以下のリソース一式を、セットアップされた状態ですぐに使うことが可能です。

* ソースコード一式（講義で用いたコードを含む）
* JDK（JDK 21）
* 統合開発環境（日本語化対応済みのEclipse）
* 各種ライブラリ（JUnit 5、Mockito、DBUnit、RestAssured、WireMock、Selenideなど）
* 負荷テストツール（Gatling）
* データベース（MariaDB）※MySQL互換
* Spring Bootによるサンプル用Webアプリケーション

本コースのソースコードは講師のGitHub上で公開していますので、それを使って個別に開発環境をセットアップすることも可能ですが、難易度が高く手間も相応にかかります。その点、この方法であれば特段のスキルは不要であり、手間もそれほどかかりません。

### Udemy講座のクーポンコード（2024年10月6日まで）

上記の『Javaテスト基礎＆実践』も含めて、現在私が講師を務めるUdemy講座には、以下のラインアップがあります。
これらのコースは、**Udedmyセールス対象外のためタイミングを気にすることなく購入可能**です。また以下のリンクから購入いただくと、クーポンが適用されたことになり、定価の**約30%OFF**で購入することができます。
|コース名|リリース|定価|クーポン適用後価格|2024年10月6日まで使えるクーポンリンク|
|--|--|--|--|--|
|**『Java Basic編』**|2023年6月リリース済|4,200円|3,000円|https://www.udemy.com/course/learn-java-se-basic/?couponCode=D862FF904549CF52EEBF|
|**『Java Advanced編』**|2023年9月リリース済|3,600円|2,500円|https://www.udemy.com/course/learn-java-se-advanced/?couponCode=7F8C5C7AB009B5FB0D92|
|**『Java テスト基礎＆実践』**|2024年7月リリース済|4,200円|3,000円|https://www.udemy.com/course/learn-java-testing/?couponCode=E7976EF1D4FF0637194F|

なお上記クーポンは期限が切れ次第、定期的に発行し、都度別のQiita記事として投稿する予定です。ぜひご活用いただけると幸いです。

### Udemyコース今後の予定

今後の計画を含めて、シリーズ全体のラインアップは、以下図のように考えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597954/1670e242-de1c-51a3-5c4a-2b967d3fc64f.png)

この9月からは新コースとして「Spring Boot3基礎＆実践」「Webの仕組み入門」「Java DBアクセス基礎＆実践」を3本並行で制作に取り掛かる予定です。
いずれも2025年3月ごろのリリースを予定していますので、興味のある方はぜひご検討ください。
AlmaLinuxにNode.js22をインストール

# 1. はじめに
node.jsをインストールする方法はざっくり2通りあるようです。

1. NodeSourceリポジトリを使用
- システム全体でNode.jsを利用する際に適している。バージョンの切り替えを頻繁に行わない環境（特に本番環境）での使用が推奨される。NodeSourceという団体が用意した手順。

https://github.com/nodesource/distributions?tab=readme-ov-file#enterprise-linux-based-distributions

2. nvm（Node Version Manager）を利用
- ユーザーレベルでのインストールが可能で、バージョン変更がしやすい。主に開発環境向けだが、本番環境でも利用可能。node.js公式の手順はこっち。

https://nodejs.org/en/download/package-manager

# 2.インストール手順
#### 1. NodeSourceリポジトリを使用してインストール

**手順:**
```bash
# curlがない場合は事前にcurlをインストール
sudo dnf install curl -y
# NodeSourceリポジトリを追加
curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash -
# nodesource-nsolid リポジトリがないといわれますが、標準のnodejsと関係ないので無視でOK
# Node.jsをインストール
sudo dnf install nodejs -y

# Node.jsとnpmのバージョン確認
node -v
npm -v
```

#### 2. nvmを利用してインストール
node.jsの公式に書いている事と同じですが、日本語のほうが分かりやすいという人もいるので載せておきます。

**手順:**

```bash
# tarがインストールされていない場合、tarをインストール
sudo dnf install tar -y
# nvmをインストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
# ターミナル再起動または一度ログアウトしてからログインしなおす
# nvmのインストール
nvm install 22
# node.jsのバージョン確認
node -v    # 本手順実施時はv22.8.0でした
# npmのバージョン確認
npm -v     # 本手順実施時は10.8.2
```

以上です。

↓dnfでappstreamからインストールする方法もあるようです。

https://qiita.com/daichi_pd/items/2c83423cb387dc87df36
Linux Mint とPostgreSQL

備忘録です。

・Linux Mint Version 22 xfce　(Ubuntu 24.04 道頓堀川に沈められていたカーネル・サンダース6.8）
・PosgteSQL 16.4 

PostgreSQLの設定ファイルの場所hはここだった
　　　　↓
/etc/postgresql/16/main
【アップデート】 AlloyDBにPostgreSQL 16がきたよ

# はじめに

2024/8/29 に[AlloyDBでPostgreSQL 16がプレビューとして利用できるようになった](https://cloud.google.com/alloydb/docs/release-notes#August_29_2024)、と発表されていました。


ちなみに、[PostgreSQL 16のリリース](https://www.postgresql.jp/node/429)は2023/9/14に、[Cloud SQL でのPostgreSQL 16のリリース](https://cloud.google.com/blog/ja/products/databases/postgresql-16-now-available-in-cloud-sql)は 2024/6/8 でした。

# AlloyDB for PostgreSQL 16を作ってみた

コンソールからAlloyDBクラスタの作成でバージョン選択に、PostgreSQL 16が出てます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2313926/ab2364f2-fefb-f51f-09d0-c48830a6cc35.png)

そのまま作成すると、無事東京リージョンでも作成することができました。
接続してバージョンを確認すると、現時点では **16.3** を利用できることがわかります。
```SQL
postgres=> select * from version();
                                         version                                         
-----------------------------------------------------------------------------------------
 PostgreSQL 16.3 on x86_64-pc-linux-gnu, compiled by Debian clang version 12.0.1, 64-bit
(1 row)
```

# まとめ

(プレビューですが)AlloyDBにもPostgreSQL 16が来ました、GA されるのが待ち遠しいですね。
16の新機能などは色々と検証結果がありますので、確認しておきましょう。

- [篠田の虎の巻：PostgreSQL 16 新機能検証結果 (GA) ](https://h50146.www5.hpe.com/products/software/oe/linux/mainstream/support/lcc/pdf/PostgreSQL_16_GA_New_Features_ja_20230919_1.pdf)
- [PostgreSQL 16検証報告](https://www.sraoss.co.jp/tech-blog/pgsql/pg16report/)
- [PostgreSQL 16とその後：技術者Blog](https://www.fujitsu.com/jp/products/software/resources/feature-stories/postgres/engineer-blog30/)
話題のCursor使ってみました、おすすめです

最近、個人的なアプリ開発をしていて、話題のCursorを使ってみました。Cursorは生成AIを付いているIDEで、非常に使いやすいです。簡単に言うと、AIとの対話を通じてほとんど手書きせずにプログラミングができるのです。

使用イメージは以下の通りである。スクリーンショットに示すように、右側のチャットでLLMに指示を与えて、その指示に基づいて生成されたコードが左側のエディタに表示されます。内容を確認し、適切であれば「Accept」ボタンをクリックすることで変更が適用されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/08052af4-a6e6-4c91-808f-916293cc2cfc.png)

あとは、コード補完機能もあり、既存コードの文脈に基づいて書こうとしているコードを自動的に予測してくれます。この機能自体はColabやCopilotなどの他のツールにもありますが、Cursorの方がより優れています。（使ってみたところ、より適切なコードが生成されます）

## Composer機能について

一般的な使い方は上記の2つですが、さらに上級機能についても紹介したいと思います。Cursorの公式ドキュメントや最新のアナウンスによると、最近「Composer」という機能を推していることがわかります。この機能は、複数のコードを同時に修正することができます。（現実のプログラミング作業により近いものになっています。少なくてもほとんどの場合、コードの修正は1つのファイルに限定されるわけではないですので）


下のスクリーンショットのように、複数のファイルを同時に修正できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/7bf2b75b-d705-15f8-bc5a-c6f415986564.png)


興味ある方は試してみてください。現在、フリーユーザーは14日間全機能を無料で使用できます。私は使い始めて数日ですが、試用期間が終わったらProにアップグレードしようと考えています。

https://www.cursor.com/
AWSスイッチロールを試す

## はじめに
スイッチロールを試します。
おそらくスイッチロールは別のアカウントにスイッチすることが多いと思いますが、今回は同じアカウントでロールだけスイッチします。別のアカウント作るのは手間なので今回は同じアカウントで仕組みだけを理解します。業務では複数のアカウントを使ってると思いますが、個人の検証なのでそこまではしません
別のアカウントにスイッチするときは、さらに設定が必要かもしれません

ユースケースでは、通常は開発環境で作業している人たちを、商用環境に切り替えるために行うのだと思います。商用環境は別のAWSアカウントなのだと思います

## 参考にした手順
- [AWS IAMでスイッチロールを使う手順](https://baresupport.jp/blog/2022/05/12/113/)
- [IAMのスイッチロールについての初心者向けガイド](https://dev.classmethod.jp/articles/iam-switchrole-for-beginner/)

## スイッチロール用のロールを作成する
ロール名：`switchRoleAdmin`  
`AdministratorAccess` 権限（ポリシー）をアタッチしています。

※別のアカウントにスイッチするときは、別のアカウントでロールを作るはずです

## スイッチ元のIAMユーザーを作成する
ユーザー名：`testuser-ec2`
権限（ポリシー）は何も付与しなくてもOK

`testuser-ec2`でAWSにログインした際、権限がないのでいろいろ参照できないエラー（赤字）が画面にでているはずです。

※別のアカウントにスイッチするときは、スイッチ元でアカウントで作るはずです

## ポリシーを作成する
ポリシー名：`switch-policy-test`  
ロールはユーザーに付与できませんが、特定のロールを使うポリシーは作成できます。以下のポリシーを作成し、そのポリシーをユーザーに割り当てることで、特定のロールを使用することができます。


```json
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::XXXXXXXXXXXX:role/switchRoleAdmin"  // アカウントIDとロール名は自身のものに合わせる。別のアカウントIDになることもある
  }
}
```
このポリシーは `switchRoleAdmin` ロールを使用するためのポリシーです。
今回はこのポリシー直接ユーザに割り当てず、グループ経由で割り当てます
XXXXXXXXXXXXはスイッチ先のアカウントですが、今回はスイッチ元同じアカウントIDです

※別のアカウントにスイッチするときは、別のアカウントでポリシーを作るはずです

## グループを作成する
グループ名：`switchRoleTest`  
グループとはポリシーを束ねたもので、今回は `switch-policy-test` をアタッチしておきます。ポリシーを直接ユーザーに付与するよりも、こちらの方が管理しやすいです。  
このグループに `testuser-ec2` を追加しておきます。

※別のアカウントにスイッチするときは、別のアカウントでグループを作るはずです

## テスト
1. `testuser-ec2` でAWSコンソールにログインします。
2. スイッチロールができるかどうかを試します。方法については次のプラグインを使用すると簡単です。

## AWS Extend Switch Roles プラグイン
[AWS Extend Switch Roles プラグイン](https://chromewebstore.google.com/detail/aws-extend-switch-roles/jpmkfafbacpgapdghgdpembnojdlgkdl?hl=ja)を使用すると、スイッチロールが簡単に行えます。通常はAWSコンソールで設定します。  

プラグインの画面を表示して、Configrationをクリックすれば設定画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131136/dcf4fe59-b45a-3bf6-7830-dca81026317d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-
設定例
```ini
[prod]
role_arn = arn:aws:iam::XXXXXXXXXXXX:role/switchRoleAdmin # アカウントIDとロール名は自身のものに合わせる
region = ap-northeast-1
color = 95ea9f
```
XXXXXXXXXXXXはスイッチ先のアカウントですが、今回はスイッチ元同じアカウントIDです
windowsでiverilog その152

# 概要　
windowsでiverilogやってみた。
SPI masterな、verilog見つけたので、テストベンチ書いてみた。

# 参考にしたページ

https://github.com/ghuangatlbl/BIDS-peripheral-drivers


# サンプルコード

```
module test;
	reg i_Rst_L;
	reg i_Clk;
	reg [7:0] i_TX_Byte;
	reg i_TX_DV;
	reg i_SPI_MISO;
	wire o_TX_Ready;
	wire o_RX_DV;
	wire [7:0] o_RX_Byte;
	wire o_SPI_Clk;
	wire o_SPI_MOSI;
	SPI_Master u (.i_Rst_L(i_Rst_L), .i_Clk(i_Clk), .i_TX_Byte(i_TX_Byte), .i_TX_DV(i_TX_DV), .o_TX_Ready(o_TX_Ready), .o_RX_DV(o_RX_DV), .o_RX_Byte(o_RX_Byte), .o_SPI_Clk(o_SPI_Clk), .i_SPI_MISO(i_SPI_MISO), .o_SPI_MOSI(o_SPI_MOSI));
	initial
	begin
		i_Clk = 0;
		i_Rst_L = 1;
	#10
		i_Rst_L = 0;
	#10
		i_Rst_L = 1;
		i_TX_Byte = 8'h55;
		i_TX_DV = 1;
		i_SPI_MISO = 1;
	#10
		i_TX_DV = 0;
	#100
		$finish;
	end
	always
	#1
		i_Clk = ~i_Clk;
	initial
	begin
		$dumpfile("test.vcd");
		$dumpvars(0, u);
	end
endmodule







```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/74bca412-698d-683e-bebc-b73059e53d97.png)


以上。
GASで行ごとのデータを列ごとにする方法＆Vlookup

### GASでgetDataRangeすると、行（横）ごとに配列になる問題

例えば
```js
const sorceData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("参照");
const sorceVal = sorceData.getDataRange().getValues();

console.log(sorceVal);
//[['請求書ID','クライアント名','契約月','契約内容','金額'],
//['123456','○○','9月','○○契約','100万円'],・・・]
```

行でわけないで～となってしまうのを、forで列ごとに入れなおす。
```js
function getColumn(vals,row){
  //すべての列をいれる配列
  column_arr =[]; 

  for(let i =0; i < vals[0].length; i++){
    //一列ごとに入れるようの配列
    column_arr[i] = [];

    for(let u =0; u < row; u++){
      column_arr[i][u] = vals[u][i];
    }
  }
  return column_arr;
}
```

上記の関数を使ってVLOOKUPできるようにしてみた

```js
const wsData =  SpreadsheetApp.getActiveSpreadsheet().getSheetByName("結果");
const wsVal = wsData.getDataRange().getValues();
const wsRow_Num = wsData.getLastRow();

function lookup(){

  //行ごとに配列に入るデータを列ごとに配列に入れなおす
  let column_arr = getColumn(sorceVal,sorceRow_Num);
  let ws_column_arr = getColumn(wsVal,wsRow_Num);

  //wsdataのA列に検索キーワード　参照のA列にも同じキーワード
  //column_arr[0]にA列すべて


  //結果シートのA列をひとつずつelementにして
  ws_column_arr[0].map((element,index)=>{

    //参照シートのA列から同じものを探して、何行目にあるか（配列の何個めか）
    let matchRow_num = column_arr[0].indexOf(element); 

    //検索結果をいれる配列
    let result = [];

    //さらに一行ごとに入れる用の配列
    let result_sm = [];

    //indexOfで値が見つからなかったときは-1になる
    if(matchRow_num !== -1){

      // 参照シートの該当行の値をすべて配列に入れていく
      for(let i =1; i < column_arr.length; i++){
        result_sm.push(column_arr[i][matchRow_num]);
      }

    }else{
      //該当なしの場合はブランク
      result_sm.push("");
    }

    //横一行に配列を入れていく方法　配列をさらに配列でくくる
    result[index] = [result_sm];

    //できた配列を一行ずつ入れていく
    wsData.getRange(index+1,2,1,result[index][0].length).setValues(result[index]);
    
  });
}

```
remixでサーバーコンソールへのエラー出力を制御する

開発しているとエラーが起きた際にスタックトレースが出力されますが、バンドルするが故に長々と謎ファイル含めたエラーが出力されます😥

スクロールも面倒だしあまり有効活用できていないので出力量を減らすことにしました

:::note info
`entry.server.tsx`に`handleError`を追加してエラーメッセージ出力をカスタマイズできます
:::

# 公式より
以下のページでhandleErrorを追加したらエラー出力をカスタムできます、とありました
https://remix.run/docs/en/main/file-conventions/entry.server#handleerror

# 対応例
追加した例が以下です
```diff_tsx
// entry.server.tsx
export function handleError(error: Error) {
  console.error("---- Oopss! Something went wrong... ----");
  console.error("[message]", error.message);
  console.error("[cause]", error.cause);
  console.error("[name]", error.name);
+ console.error("[stack]", error.stack?.split("\n").slice(0, 6).join("\n"));
}
```

強調表示したところがスタックトレース出力行数の制限になってます
上記は削除した分は見られなくなってしまうので、ログファイルを記録するようにするといいかもしれませんね
【Firebase】Must select at least one feature. Use SPACEBAR to select features, or specify a feature by running firebase init [feature_name]の解決方法

# はじめに
Firebaseの設定を行なっている際にfirebase initを実行したら発生した下記エラーの解決方法について解説します。

# エラー内容
firebase initを実行が次のようなエラーが出ました。

```
firebase init

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /Desktop/dev/jisou/p-typescript-todo-app

? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. 

Error: Must select at least one feature. Use SPACEBAR to select features, or specify a feature by running firebase init [feature_name]

```

***Must select at least one feature. Use SPACEBAR to select features, or specify a feature by running firebase init [feature_name]***

# 原因
Hostingを選択するときに***spaceキー***を押さずに***enterキー***を押していることが原因でした。この状態ではFirebase CLIの機能の選択ができていないのでエラーになってしまいます。

# 解決方法
エラー分にもあるとりspaceキーを押すことでFirebase CLIの機能の選択ができます。
その後にentaerキーを押すことで解決できます。

# 終わりに
エラーが出てしまうとどうしても焦ってしまいますが、しっかり読んだら調べなくても解決できそうでしたね...
Unity ECS CollisionFilterの取り扱いについて

## UnityESCは、CollisionFilterの説明が不足している

ECSを使ってゲーム作りしていると、CollisionFilterを使いたい場面は多いと思います。
しかしながら、Unity公式にアクセスしても情報が足りない！
ググっても全然情報が無い！
英語の記事すらも全然見つからない...!

という訳なので、記事に残そうと思います。
MonoBehaviorとはかなり違い、ややこしいです。効率的な計算の代償として、人間が扱いずらい設定方法になっているのでしょう。

まずInspectorでの設定ですが、これはMonoBehaviorとそこまで変わりません。
以下のように、Physics Shape内のColllision Filter内で、Belongs ToやCollides Withを設定すればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715582/6ff16051-af05-535d-3039-c46ff45a733f.png)

次にScript側での設定。MonoBehaviorでいうところのOntriggerEnter的な機能とか、Raycastを使いたい場合は、Script上で設定する必要があります。

例えばレイヤー2.3.4と接触させたい場合は、以下のようにします。
`
uint collidesWithLayers = (1u << 2) | (1u << 3) | (1u << 4);
`
こんな分かりずらい記述をする理由ですが、

まず`1u`の意味は、
`1u = 00000000 00000000 00000000 00000001  (二進数)`
です。

`<< 2`すると、2ビット左に移動するので、
`1u << 2 = 00000000 00000000 00000000 00000100 `
となります。
※つまり、 1u << 2 の結果は 4です。

そもそもレイヤーは以下のように定義されています。

`1u << 0 は 00000000 00000000 00000000 00000001` なので「Layer 0」を意味します。
`1u << 1 は 00000000 00000000 00000000 00000010` なので「Layer 1」を意味します。
`1u << 2 は 00000000 00000000 00000000 00000100` なので「Layer 2」を意味します。

例えば以下のようなスクリプトです。
```
RaycastInput raycastInput = new RaycastInput
{
    Start = ray.origin,
    End = ray.origin + ray.direction * 1000f,
    Filter = new CollisionFilter
    {
        BelongsTo = ~0u, //全レイヤーと接触する
        CollidesWith = (1u << 0) | (1u << 2) //レイヤー0,2と接触する
    }
};
```

以下動画では、Entityに対してマウスからRayを発射し、当たり判定を元にStatusWindowを表示したり消したりしています。Colllision Filterの設定により、キャラクター以外にマウスポイントのRayが当たっても反応しません。

https://x.com/i/status/1827724410603860283

Twitterにゲーム作成経過を記録しているので、是非フォローしてください。


以上
Linux Ruby 3.3.5 update メモ (rbenv)

# 環境
H/W : HP ENVY x360 Convertible 13-ar0xxx(CPU:Ryzen7 3700U Mem:16GB)
OS : Linux(Debian12 bookworm on WSL2)
Host OS : Windows11 Home 23H2

# はじめに
インストールの記事は書いてるけど、そういやrbenvを使ったバージョンアップについて書いてないので投稿したいと思います。

# 参考URL
[「gem update --system」と「gem update」の違い](https://qiita.com/tatama/items/4e9d6bb8bfa2d9556db7)
[LinuxでRuby 2.5.0 インストールメモ](https://qiita.com/edward999th/items/823ccb1fd88eabc93190)
[【Ruby】インストール済みのGemを確認する方法](https://qiita.com/tetusan/items/ac59833b0f91e92c623f)

# 前提
過去記事の[Linux Ruby3.3.1インストール完全に理解した(rbenv)](https://qiita.com/edward999th/items/e6479a356be11d53db51)の続きです。
インストールパスや各ディレクトリの所有者（グループ）設定、権限設定は前回の記事どおりの設定となっている前提となります。

# Rubyのupdate

## git pullでruby-buildを最新化する

```:bash
$ ruby -v
ruby 3.3.2 (2024-05-30 revision e5a195edf6) [x86_64-linux]
$ cd "$(rbenv root)"/plugins/ruby-build
$ git pull
fatal: detected dubious ownership in repository at '/usr/local/lib/rbenv/plugins/ruby-build'
To add an exception for this directory, call:

        git config --global --add safe.directory /usr/local/lib/rbenv/plugins/ruby-build
```
上記の様に`git pull`でエラーとなります。
~~これは該当ディレクトリの所有者がrootなのでたとえrubyグループで読み書き実行の権限があったとしてもlocalアカウントではgitのポリシーでpullが実行できないためです。~~

```:bash
$ git config --global --add safe.directory /usr/local/lib/rbenv/plugins/ruby-build
$ git pull
error: cannot open '.git/FETCH_HEAD': Permission denied
```
エラーメッセージにあった`git config ～`を実行しましたが、今度は'Permission denied'エラーとなりました。


~~結局、root権限(sudo)で`git pull`を実行しました。~~
（以下訂正・追記）
.git配下を見たら所有者root、グループrootになっているファイルが複数ありました。
おそらく以前updateしたときにroot権限で作業したためです。
rbenvディレクトリ配下のグループ所有権をrubyに変更し、読み・書き・実行の権限を付与すればローカルアカウントで管理（updateなど）できるようになります。

```:bash
$ cd /usr/local/lib/
$ ls
rbenv
$ sudo chgrp -R ruby rbenv
$ sudo chmod -R g+rwxX rbenv
$ ls -l
drwxrwxr-x 14 root ruby 4096 May 22 10:56 rbenv
```

気を取り直して、`git pull`します。
```:bash
$ cd "$(rbenv root)"/plugins/ruby-build
$ git pull
（略）
$ rbenv install --list
3.1.6
3.2.5
3.3.5
jruby-9.4.8.0
mruby-3.3.0
picoruby-3.0.0
truffleruby-24.0.2
truffleruby+graalvm-24.0.2

Only latest stable releases for each Ruby implementation are shown.
Use `rbenv install --list-all' to show all local versions.
```

## 3.3.5インストールとバージョン切替え
```:bash
$ rbenv install -v 3.3.5
（略）
==> Installed ruby-3.3.5 to /usr/local/lib/rbenv/versions/3.3.5
$ rbenv versions
  3.3.1
* 3.3.2 (set by /usr/local/lib/rbenv/version)
  3.3.5
$ rbenv global 3.3.5
$ ruby -v
ruby 3.3.5 (2024-09-03 revision ef084cc8f4) [x86_64-linux]
```

# Gemのupdate
gemコマンド(RubyGems)本体のupdateと各gemモジュールのupdateの二種類あります。

## gemコマンド(RubyGems)本体のupdate
`--system`オプションを付けるとgemコマンド本体のupdateになります。
今回は3.5.16から3.5.18へupdateしました。
```:bash
$ gem -v
3.5.16
$ gem update --system
（略）
RubyGems system software updated
$ gem -v
3.5.18
```

## Gemモジュールのupdate
オプションなしで全Gemモジュールのupdateを実行します。
```:bash
$ gem update
Updating installed gems
（略）
```
ターゲットのGemのみupdateしたい場合は`gem update [GEMNAME]`の様にGemの名前を指定します。
　
## インストール済Gemとバージョン確認
```:bash
$ gem list

*** LOCAL GEMS ***

abbrev (default: 0.1.2)
（略）
```
`-d`オプションを付けると詳細な情報が表示されます。

# おわりに

ちょっとしたことでもすぐに忘れるのですぐに見返せるようメモを作っておくと便利です。
Self-hosted GitHub Actions runners for automated Amazon ECS deployment

Code の修正を Trigger にした Amazon ECS ( ECS ) への Deploy について。

参考にしたのは、GitHub の公式。

https://docs.github.com/ja/actions/use-cases-and-examples/deploying/deploying-to-amazon-elastic-container-service#creating-the-workflow

構成は、こんな感じ

```mermaid
flowchart TD
    subgraph AWS
        subgraph ECS
            task_def["Task Definition"]
            service["Service"]
            Task
        end
        ECR
        codebuild[CodeBuild]
        ALB
    end
    subgraph github[GitHub]
        src[Src]
        subgraph environments[Environments]
            development[Development]
            staging[Staging]
            production[Production]
        end
        subgraph Actions
            docker_build["docker build"]
            describe_task_def["aws ecs describe-task-definition"]
            amazon_ecs_render_task_def["amazon-ecs-render-task-definition"]
            amazon_ecs_deploy_task_def["amazon-ecs-deploy-task-definition"]
            Json
        end
    end
    Developer -->|Commit| src
    src -->|Trigger| Actions
    docker_build --> describe_task_def
    describe_task_def --> Json
    docker_build -->|Push image| ECR
    describe_task_def --> amazon_ecs_render_task_def
    amazon_ecs_render_task_def --> amazon_ecs_deploy_task_def
    amazon_ecs_render_task_def -->|新しいリビジョンの作成| task_def
    Json --> amazon_ecs_render_task_def
    ECR -->|Pull image| Task
    amazon_ecs_deploy_task_def -->|サービスを更新| service
    task_def --> service
    service --> Task
    ALB --> Task
    Tester --> ALB
    environments --> Actions
```

## Sum up

- k8s で ArgoCD などの GitOps で運用している場合、Helm chart の yaml を更新したら終わりのため、楽ではある。
- 一方、k8s や周辺の ecosystem の更新に追われることを考えると ECS の方が健康的に過ごせるよなというのは正直ある。


## 環境変数

- Self-hosted において、環境変数は、GitHub の `Environments` に設定する。CodeBuild の環境変数は使えない。
    - GitHub `Environments` は、2021年に登場した機能らしい。
    - 前職では、Cloud Build をメインで使用していた。Managed Service を優先的に使用した。
    - 理由は、Actions の容量を超えて、Build や Deploy が停止することが多発したため。

![settings](/images/d6b7e8a94a492e-a.png)

## Workflow

- 変更点。Json を出力して、最新のタスク定義を使い回す。

```yaml: .github/workflows/build-hoge-api.yml
      - name: Latest ECS task definition Json
        id: create-json
        run: aws ecs describe-task-definition --task-definition ${{ env.ECS_TASK_DEFINITION_ARN }} --query taskDefinition > taskdefinition.json

      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: taskdefinition.json
          container-name: api
          image: ${{ steps.build-image.outputs.image }}
```

## Conclusion

中学校の職場体験に在宅 programmer をお勧めしましたが、笑ってスルーされました
Cloud Functions + Selenium でスクレイピングしている時にメモリエラーが出たときの対処法

Cloud Functions で headless chromium を使っている際にメモリエラーが発生したときの調査メモです。

## 結論

Chrome driver を一旦止めてから再開することで回避できます。

```python
def get_driver():
    ...
    return return webdriver.Chrome(service=service, options=options)


driver.quit()
driver = get_driver()
```

## 現象

`driver.get(url)` を実行する回数が多い時にメモリエラーが発生する。
具体的には次のようなログが出力される。
```
'Memory limit of 2048 MiB exceeded with 2060 MiB used. Consider increasing the memory limit, see https://cloud.google.com/functions/docs/configuring/memory'
````


## やったこと

どこでメモリを消費しているのか調査しました。

### memory-profiler を使った調査

詳細は割愛しますが、実行している関数のどの部分でメモリを消費しているか行単位で確認できます。
確認した結果、python プログラムはたかだか 80MB しか使っていなかったため、Chrome でメモリを消費している可能性が高いと判断しました。

### driver の停止と再開

何回か `driver.get()` を実行したら `deiver.quit()` を実行します。

```python
for i, url in enumerate(urls, 1):
    driver.get(url)
    if i % 10 == 0:
        driver.quit()
        driver = get_driver()
```

これでエラーが出なくなりました。

### 実用的な問題

読み込むページ数が多いサイトを扱うごとに上記のような driver.quit() を挟むような実装をするのは効率が悪いため避けたいです。
自作の get_deriver 関数は様々なスクレイピング対象のサイト用のスクリプトから呼び出しているため、WebDriver のラッパーを作って get_driver を改修しました。


```python
def get_driver():
    return WebDriverWrapper()


class WebDriverWrapper:
    def __init__(self):
        self.driver = self._create_driver()
        self.load_count = 0
        self.max_loads_before_quit = 10  # 任意の回数に設定

    def _create_driver(self) -> webdriver.Chrome:
        """新しい webdriver.Chrome インスタンスを作成する"""
        options = webdriver.ChromeOptions()
        # 略
        return webdriver.Chrome(service=service, options=options)

    def _restart_driver(self):
        """ドライバーを再起動する"""
        self.driver.quit()
        self.driver = self._create_driver()
        self.load_count = 0

    def get(self, url):
        """get メソッドのラッパー"""
        if self.load_count >= self.max_loads_before_quit:
            self._restart_driver()

        self.driver.get(url)
        self.load_count += 1

    def __getattr__(self, name):
        """get メソッド以外はオリジナルのドライバメソッドを返す"""
        return getattr(self.driver, name)

    def quit(self):
        """明示的にドライバーを終了する"""
        if self.driver:
            self.driver.quit()
            self.driver = None
```

これで get メソッドを10回使うたびにドライバーを再起動することができます。
[WIP]Amplify and Custom Resources

Amplify Gen 2 を 5 ヶ月ほど使用した感想と現在地について。

https://docs.amplify.aws/react/

## tl;dr

- Custom Resources で全て構成するのは難易度が高い。

## Dry run が欲しい

- Terraform でいう `terraform plan`、AWS CDK でいう `cdk diff` [^1] が存在しない。
- deploy はいつも一か八か。
- 本番運用を諦めた原因の 1 つ。

## CloudFormation が壊れがち。

> ご共有いただきましたログに記録されている「current_account-current_region」は、Amplify Gen 2 が内部的に使用している CDK にて、CDK が内部的に使用しているアセット の destinationId の値となります。
成功する場合にも「current_account-current_region」はコマンドの出力結果に含まれますので、現時点でこちらが当該事象の要因ではないと考えております。

- サポートに確認済み。
- これについては詳しい原因は掴めていない。ただ、突如として失敗する。結果、Stack を全消しすることに。
- 本番運用を諦めた原因の 1 つ。

## Amplify のビルドでは、Docker in Docker を使えない

> ご希望に沿った回答とならず心苦しいのですが、現在の Amplify の CI/CD パイプラインにて docker build することはできません。

- サポートに確認済み。
- pipeline 内で `docker build` できない。
- Amplify の自動ビルドを無効化して、CodeBuild で CI/CD を動かす必要があった。

## Conclusion

Amplify Gen 2 は、色々と課題がありましたが、AWS 初心者としては、Google Cloud との違いや、AWS のサービス群について学ぶ良い機会だった。

このまま突っ走ることも出来なくはなかったと思うが、時には計画を変更する勇気も必要だと思う。

なぜなら、わたしたちはベンチャー企業であり、豊富なリソースがあるわけではなく、限られたリソースで局地戦を戦う必要があるから。

そのためには、安定感とチャレンジのバランスが必要。

[^1]: https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/ref-cli-cmd-diff.html
What about Marp?

Marp について。

https://marp.app/

スライドを Markdown で作成できるツール。

アイスブレイクのスライドを作る機会があったので利用感を確認した。

https://github.com/danny-yamamoto/Here-s-my-high-school.

## tl;dr
- 画像は root ディレクトリに配置する。Export するとき、サブ ディレクトリだと画像を表示できない。
- スタイルの変更は CSS が必要。
- Export は PDF や パワポなどに対応している。Google スライドで表示したければ、パワポをインポートしたら OK
- HTTP バッファサイズの調整が必要。

## 画像

- Markdown の書式の通り。画像の配置だけ気をつける。

https://github.com/danny-yamamoto/Here-s-my-high-school./blob/3d388e6630f660f17ba0ea4f9c9eb92aeb81e502/intro.md?plain=1#L48

## スタイル

### 全体のスタイル

- 細かいあれこれは CSS で定義する。
- ヘッダーにある `theme` が重要。これを認識してスタイルを当てている。

https://github.com/danny-yamamoto/Here-s-my-high-school./blob/3d388e6630f660f17ba0ea4f9c9eb92aeb81e502/custom.css#L1

```bash
touch custom.css
mkdir .vscode/
touch .vscode/settings.json
```

https://github.com/danny-yamamoto/Here-s-my-high-school./blob/main/.vscode/settings.json

https://github.com/danny-yamamoto/Here-s-my-high-school./blob/3d388e6630f660f17ba0ea4f9c9eb92aeb81e502/custom.css#L1

https://github.com/danny-yamamoto/Here-s-my-high-school./blob/3d388e6630f660f17ba0ea4f9c9eb92aeb81e502/intro.md?plain=1#L3

### 個別のスタイル

https://github.com/danny-yamamoto/Here-s-my-high-school./blob/3d388e6630f660f17ba0ea4f9c9eb92aeb81e502/intro.md?plain=1#L85-L87

## Marp のコードを push できない

- HTTP バッファサイズの制限が原因でエラーが発生した。
- `git config http.postBuffer 524288000`

```bash
git push origin main:main
error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400
send-pack: unexpected disconnect while reading sideband packet
fatal: the remote end hung up unexpectedly
Everything up-to-date
```

## Conclusion

風物詩が来た。

目標管理。

大人の文章を書いて、ゴニョゴニョするアレです。

現職になって初めての目標管理だが、割とすぐまとめることができた。

提供する価値と VALUE が確固たるものであれば、迷うことはない。

逆に、VALUE が飾りであれば、顔を伺いながら仕事をしなければならない。

VALUE は創業者が書くものだと思う。決してボトムアップで作るものではないと思う。

https://x.com/saksak_inv/status/1743957230909845750

環境にこだわれ
Redisのnode, shard, clusterとは

## 概観

![ElastiCache-NodeGroups.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/e847ea46-025a-91b1-d930-09000944fd0f.png)

## nodeとは
- 1つのDB
  - primary node : 読み・書きができる
  - replica node : 読みだけできる

## shardとは
- primary node ( + replica node)
- `node group`とも呼ばれる

## clusterとは
- shard * n

## 参考文献
- [Redis OSS nodes and shards](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/CacheNodes.NodeGroups.html)
CLS出島 #0 イベントレポート

## はじめに

CLS出島 #0 に運営メンバーとして参加してきました！

https://peatix.com/event/4048068

長崎県各地と、県外から集まった濃いメンバーで、コミュニティについて学び、議論しました

## 参加経緯

私は大分のコミュニティ、 [JAWS-UG 大分](https://jawsug-oita.connpass.com/) 、 [JBUG](https://jbug.connpass.com/) 大分 、 [Cloudflare Meet-up](https://cfm-cts.connpass.com/) 大分 などなどに所属し、定期的に勉強会を開催しています

https://qiita.com/RyoWakabayashi/items/f93cb7a5c2932958172d

https://qiita.com/RyoWakabayashi/items/1f473a039ce3e7e0ab4c

その流れで CLS = コミュニティリーダーズサミット 高知にも参加してきました

https://qiita.com/RyoWakabayashi/items/ffcc3f9ad1fd02721ee0

CLS 高知の後夜祭で長崎県から来ていた古地さんと知り合い、 CLS 出島の話を伺いました

https://x.com/yuunakochi/status/1791858377603355102

そのまま同じ九州、大分県や佐賀県から来ているメンバーで、 CLS 経験者として運営に関わらせて頂くことに

https://x.com/yuunakochi/status/1800867886963323138

ほんの少しのお手伝いしかしていないので、楽しませてもらって勉強させてもらってばかりの感じではありますが、運営として関われてよかったです

## 会場

長崎駅近くのコワーキングスペース co-dejima で開催しました

https://co-dejima.jp/

早めに来たので社内業務もやりました

すごくオシャレで快適で働きやすかったです

https://x.com/yuunakochi/status/1831932094685311249

https://x.com/nakaji573/status/1831955749368668555

https://x.com/nakaji573/status/1831963832954319155

## インプットトーク

最初にインプットトークとして、[コミュニティマーケティング推進協会](https://communitymarketing.jp/)の小島さん、北川さんからコミュニティマーケティングの話を伺いました

<script defer class="speakerdeck-embed" data-id="d27908fe7e69450f8f1c9ef4c73598c0" data-ratio="1.7772511848341233" src="//speakerdeck.com/assets/embed.js"></script>

私自身、技術コミュニティの運営に入っているので共感すること、勉強になることがたくさんありました

https://x.com/atuykunkamuy/status/1831994532462034944

https://x.com/yuunakochi/status/1831999466821566578

## ディスカッション

「自分自身が HUB となって越境する人になりたいか、そういう人を呼びたいか、またそのためにはどうすれば良いのか？」

長崎県地元の方々の中に「CLS伝道師」として入り、ディスカッションしました

私自身、まだその答えが見えていない中で、ファシリテーションも上手くはないので中々難しかったです

私自身は最初に福岡の Elixir コミュニティ [fukuoka.ex](https://fukuokaex.connpass.com/) に参加したのがコミュニティの始まりで、そこから「大分にもコミュニティあるの？」と思って見つけた JAWS UG 大分に入っています

当時はコロナ禍もあって、大分県でほとんど勉強会イベントがなく、「どうにかしないと大分やばいのでは？」と焦ったのを覚えています

そこから先日の OITA-N Web 祭り開催まで、たくさんの人に巻き込まれ、巻き込み、色々なイベントに関わることができて、元々人間関係が苦手な私としては、かなり関係人口も広がりました

https://qiita.com/RyoWakabayashi/items/3ab739a7fff28e648511

最近、「色々コミュニティに参加して、運営もしてきて、じゃあこれから何を目的にするのか、ゴールにするのか、私は何をしたいのか」を考えることがあります

今回改めて、 CLS 出島がそれを考える機会になったと思います

それぞれのコミュニティにはもちろんそれぞれの目的があって、でも、それらを繋げて横に広げるとやっぱり色々な反応が起こって面白く、でも単に目的なく「繋げた」だとそれだけで終わってしまい、、、

CLS 出島のような、地域のコミュニティ関係者が集まって議論する場を作りたい！と思いつつ、「そのゴールは何？」という問いの答えはまだ出ていません

## 観光情報

長崎に着いて最初のお昼ご飯はトルコライスをいただきました

カツがすごく柔らかくて美味しかったです

昔ながらの喫茶店で、雰囲気も良かったです

https://tabelog.com/nagasaki/A4201/A420101/42003981/

宿泊したのは「ぶらぶら」です

オシャレな館内、でも周りはローカルな漁村で、通な旅気分を味わえました

海が全面に見える部屋に泊まったので、とにかく景色が綺麗でした

https://nagasakihouse.com/

https://x.com/nakaji573/status/1832235578089468267

懇親会の料理も最高でした！

https://x.com/nakaji573/status/1832023590642081852

翌朝の散歩もさわやかで、地元のパン屋さんのパンが美味しかったです！

（この後ちゃんぽんも食べたいのにパンを2個食べてしまった＆1個お土産）

https://tabelog.com/nagasaki/A4201/A420101/42000807/

https://x.com/sugimisu/status/1832209409004728630

## まとめ

まずは長崎が楽しかったです！

そして、改めてコミュニティについて考える機会にもなりました

引き続き、 Elixir と AWS と Backlog と Cloudflare と大分県を推していきつつ、コミュニティについて考えていきます
CodeIQ:「ディビジョン・サム」問題

Kawazoe(@riverplus)さんのCodeIqの問題です。
問題はこちらの御世話になりました。解答例もあります。
->https://sw-logic.com/Portfolio/Programing/CodeIQ/2903.php
こちらにも情報があります。
->https://togetter.com/li/1049668
テストケースはあちこちから集めた気がします。

ほかにもテストケースのデータがあったようです。今まで気が付きませんでした。(2025.5.3追加)
->https://sangaku0418.hatenablog.com/entry/2016/12/01/100100
有難く参照させていただきデータを追加しました。

例えばz=x^2\*y^3(x,y素因数)とすると、zの約数は、
　x^0\*y^0,x^0\*y^1,x^0\*y^2,x^0\*y^3
　x^1\*y^0,x^1\*y^1,x^1\*y^2,x^1\*y^3
　x^2\*y^0,x^2\*y^1,x^2\*y^2,x^2\*y^3
となり合計は
x^0\*Σ(0<=k<=3)(y^k)+x^1*Σ(0<=k<=3)(y^k)+x^2\*Σ(0<=k<=3)(y^k)
=Σ(0<=h<=2)(x^h)\*Σ(0<=k<=3)(y^k)
素因数やその指数が増えても同様です。
更にΣ(0<=h<=m)(x^h)=(x^(m+1)-1)/(x-1)
そしてn!^nのある素因数の指数はn!のその素因数の指数のn倍です。

Juliaではfactorが使えますがパッケージをインストールしないといけませんので、
自前で(n!)^nの素因数を調べるfactor1を実装しました。
n!の素因数分解はルジャンドル関数を用いて求めることができます。
つまりn!を素因数分解すると素数pの数はΣ(p<=p^i<=n)div(n,p^i)
factor1では同時に素数も求めています。n以下のすべての素数が素因数です。
その後約数の和の計算をします。結果は大きな数になりますのでBigIntを使います。
(BigIntを使わないとinvmodという関数が必要のよう)
2024.9.7追加->カッコ内はinvmodを使った場合のみ解けたという意味です。

```Julia
#import Pkg;Pkg.add("Primes")
#import Primes: isprime, primes, primesmask, factor

 function solve46(n,a)
  function factor1(n)
  #ルジャンドル関数を利用
    for i in 2 : n
      x = 0
      if ar2[i] != 0　　#　iが素数なら
        k = i
        for j in i : i : n
           ar2[j] = 0　　# iの倍数は素数ではない　
           if j == k    # jはiの累乗
              x += div(n,j)
              k *= i　　#　kはiの累乗　
           end
        end
        ar1[i] = x*n
      end  
    end
  end
  ar1 = zeros(Int,n)
  ar2 = Array(1:1:n)
  m = 1000003
  ret = big(1)
  factor1(n)
  for i in 2 : n
    if ar1[i] != 0
       x = big(i)
       ret = mod(ret * div(x^(ar1[x]+1)-1,x-1),m)
    end
  end
  s = a == ret ? "ok " : "no "
  println(s,ret)
end

solve46(2, 7)
solve46(3, 600)
solve46(4, 991111)
solve46(12, 845575)
solve46(630, 951018)
solve46(997, 772380)
solve46(1000, 985788)
#2025.5.3追加
solve46(11, 687005)
solve46(99, 820272)
solve46(264, 398251)
solve46(610, 823587)
solve46(912, 210178)
```
Prologではコードが複雑にならないように先に素数を求めています。
それでfactor/4はルジャンドル関数だけを実装していますので
NをK^iで割るのではなく、
NをKで割った商をさらにKで割りつつ商を合計しています。
その後calc44で約数の和を計算します。
sumfac/2では素数のリストと、素因数の数を入れるリストを作ってfac/4を呼び、
fac4ではすべての素数をfactor/4に送り、結果をN倍してリストに入れています。
SWI-Prologは多倍長整数ですので、大きな数でも問題ありません。
（投稿時私の環境ではideoneでJavaしか表示されず実行できません）

```Prolog
%SWI-Prolog ver 7.42,7.64,9.25
%:-initialization(start).   %(Online Prolog Compiler.)
%start.

factor(N,X,R,R):-X>N,!.
factor(N,X,R1,R):-N1 is N div X,R2 is R1+N1,factor(N1,X,R2,R).

fac([],_,R,R):-!.
fac([H|P],N,L,R):-
   factor(N,H,0,V),V1 is V*N,
   nth1(H,L,_,L1),nth1(H,R1,V1,L1),fac(P,N,R1,R),!.

sumfac(N,R):-length(L,N),maplist(=(0),L),prime(N,P),fac(P,N,L,R).

prime(2,[2]).
prime(N,R):-
   N1 is N-1,prime(N1,R1),
   (forall(member(X,R1),(N mod X=\=0))->R=[N|R1];R=R1).

calc(1,_,1).
calc(N,L,R):-
   N1 is N-1,calc(N1,L,R1),nth1(N,L,X),
   (X=:=0->Y=1;Y is (N^(X+1)-1) div (N-1)),R is (R1*Y) mod 1000003.

solve(N,R):-sumfac(N,L),calc(N,L,R1),R is R1,!.% mod 1000003,!.

start:-
   f(N,A),(solve(N,R)->(R==A->Str=" ok  ";Str=" no  ");
    write(fail)),write(" "),write(Str),writeln(R),fail.
start.



```
[PHP] 可読性0の短めなbase64エンコード・デコード関数 (v2)

この記事は、以下の記事に書いたやつがさすがにゴミだったので、その改訂版です

https://qiita.com/UziDeer/items/a624bf1b06c17fc24fee

```b64fn.php
    $b64Arr = array_merge(range("A", "Z"), range("a", "z"), range("0", "9"), ["+", "/"]);

    function b64safe(string $b64, bool $dec = false, array $rep = [["+", "/", "="], [".", "_", "-"]]):string {
        return str_replace($rep[(int) $dec], $rep[(int) !$dec], $b64);
    }

    function blockPad(string $str, string $pad, int $len, bool|int $right = false) {
        $i = 0;
        while ($i < strlen($str)) $i += $len;
        return str_pad($str, $i, $pad, (int) $right);
    }

    function bin2b64(string $bin):string {
        return blockPad(implode("", array_map(fn($v) => $GLOBALS["b64Arr"][bindec($v)], str_split(blockPad($bin, "0", 6), 6))), "=", 4, true);
    }

    function b642bin(string $b64):string {
        return implode("", array_map(fn($v) => str_pad(decbin(array_search($v, $GLOBALS["b64Arr"], true)), 6, "0", 0), str_split(str_replace("=", "", $b64))));
    }

    function b642intArr(string $b64, int $spl = 5):array {
        return array_map(fn($el) => intval(b642bin($el), 2), str_split(blockPad($b64, "A", $spl), $spl));
    }
```


<table>
  <thead>
    <tr>
      <th>関数</th> <th>引数</th> <th colspan="2">引数の説明</th> <th colspan="2">返り値</th>
    </tr>
  </thead>
  <tr>
    <td rowspan="4">b64safe()</td> <td>$b64</td> <td colspan="2">入力するbase64</td> <td rowspan="4">$repのルールによって<br>エンコード/デコードされたbase64</td>
  </tr>
  <tr>
    <td rowspan="2"> $dec </td> <td>false</td> <td>エンコード</td>
  </tr>
  <tr>
    <td>true</td> <td>デコード</td>
  </tr>
  <tr>
    <td> $rep </td> <td colspan="2">変換ルールの指定</td>
  </tr>
  <tr>
    <td rowspan="4">blockPad()</td> <td>$str</td> <td colspan="2">入力する文字列</td> <td rowspan="4">$lenの倍数の長さになるように<br>paddingされた文字列</td>
  </tr>
  <tr>
    <td> $pad </td> <td colspan="2">padに使用する文字</td>
  </tr>
  <tr>
    <td> $len </td> <td colspan="2">pad後の文字列の倍長</td>
  </tr>
  <tr>
    <td> $right </td> <td colspan="2">paddingする方向</td>
  </tr>
  <tr>
    <td>bin2b64()</td> <td>$bin</td> <td colspan="2">入力するbinary_string</td> <td>$binからbase64へ変換した文字列</td>
  </tr>
  <tr>
    <td>bin2b64()</td> <td>$b64</td> <td colspan="2">入力するbase64</td> <td>$b64からbinaryへ変換した文字列</td>
  </tr>
</table>