OmniAICreator/Qiita-1.07M huggingface dataset:
Rails7 リロードしないとフォームのsubmitボタンが反応しなかった話

お久しぶりです。9月にニートから業務委託に昇格し、将来はドローンパイロットになりたいとよくわからないことを思い始めている変人です。

今回は、業務委託中で起こった、`formをリロードしないと送信できない！Turbo.falseにしたい！（発狂）`事件についてお話しようと思います。

#### 現象
- 新規投稿・編集画面に遷移後、入力欄に記入はできる。
- `でも、submitボタンが効かない！！`
- rails consoleで保存はできている。
- ブラウザでリロードしたら、submitできる。

#### 原因
`<div></div>`のそれぞれの個数が合っておりませんでした（笑）「死にそうです、Turbo切りたいです」とほざいておきながら、divタグをまともに閉じれていませんでした（ポンコツ超えてアホですね笑）

大まかには下記のようになっていました。

```ruby:_form.html.erb
<div class="hamster">
  <%= form_with model: @hamster, local: true do |f| %>
    <div class="form">
        <%= f.label :name %>
        <%= f.text_field :name %>
    </div>
    <div class="form">
      <%= f.label :gender %>
      <%= f.select :gender, Gender.pluck(:gender, :id) %>
      <%# 閉じタグがここにない🐹 %>
    <div class="action">
      <%= f.submit %>
    </div>
  <% end %>
</div>
```

なので、まず、「Turbo切りたい」と言い出す前に、開始タグと閉じタグの個数を確認してみてください。
意外とフォームが送信できない原因がここにあったりします笑（特に睡眠不足で疲労困憊の方）

#### 参考にした記事
[[Rails]リロードしないと投稿できないちょっとした不具合](https://qiita.com/taro03/items/4973c1c14798c1601d6e)

#### 最後に
お読みいただき、ありがとうございました！
時間があるときに、業務委託の経験を書いていこうかなと思います笑
テーブル構造を考える①（データモデル編）

データベースの設計は、次の手順で行います。

1. 概念データモデルを作成する
2. 導入するDBMSに合わせて論理データモデルに変換する

本記事では、データモデルの説明をします。次の記事で、続編として正規形の話をします。
これらの記事により、テーブル設計を行う際に最低限の基準が分かると思います。

具体例から大雑把に学びたい方は、[テーブル構造を考える③（具体例）](https://qiita.com/ruuuuu/items/4d0159a1fb6730fbf28a)へどうぞ。

## データモデル
データベースを構築する範囲を**対象世界**と呼び、対象世界をモデル化したものが**データモデル**です。データモデルを作成することを**データモデリング**と言います。対象世界を抽象化し、概念データモデル（概念モデル）を作成します。概念データモデルをデータベースとして実装可能な論理データモデル（論理モデル）へと変換します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897889/61fe156c-8529-7d71-8877-32706d953fc6.png)

### 概念データモデル
**概念データモデル**は、対象世界のデータ構造を概念的に捉えた結果を表現したモデルです。概念データモデルの記述には**ER図** が良く用いられます。ER図は、**Entity（実体）** と **Relationship（関連）** から構成されます。Entityは管理対象とするデータの集合体を、RelationshipはEntity間のつながりを表します。
Relationshipにおける多重度を**カーディナリティ**と呼びます。カーディナリティは、あるEntityが保持する1件のデータが、関連するEntityの何件のデータに対応するかということを表しています。
以下の図は、Entity間を直線で結んでRelationshipを表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897889/569dce95-3ff4-d7c7-99c8-27baf7a11b8e.png)

### 論理データモデル
論理データモデルは、データとデータ間の関係を論理的に表現したもので、そのままデータベースとして実装可能なデータモデルとなっています。論理データモデルには、DBMSがデータを保持するための論理構造に応じて、関係モデル（リレーショナルモデル）、階層モデル、ネットワークモデルなどがあります。

## データベース設計
先に説明したように、データベースは以下の手順で作成します。

1. 概念データモデルを作成する
2. 導入するDBMSに合わせて論理データモデルに変換する

論理データモデルとして、関係モデルを採用することを前提に、それぞれの手順について説明します。

### 概念データモデルの作成
最初に、管理対象とするデータを対象世界から抽出し、Entityとして定義します。抽出するデータは、商品、取引先などのように実態が物理的に存在するデータだけでなく、売上、出荷などのように物理的な実態が存在しないデータについても検討します。概念データモデルを作成するときのポイントは、「対象世界はどうあるべきか」、「対象世界ではどのようなデータを保持すべきか」という視点で業務を俯瞰的に捉えながらデータを抽出することです。
Entityを抽出できたら、Entityごとに主要な属性（データ項目）を明確にします。詳細な属性は論理データモデルの作成で洗い出すので、Entityを具現できる最低限の属性で十分です。例えば、Entiry「商品」であれば、商品コードと商品名程度でよいと考えられます。以下の図では、Entityを長方形で表し、Entityの名称を上段に、主要な属性を下段に示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897889/12ee33e2-def7-fd33-2648-a7a0e027893e.png)

次に、Entity間のRelationshipを明確にします。EntityとEntityの間に関係がある場合、Entity間に線を引きます。合わせて、カーディナリティも明確にしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897889/4dd5228d-3a50-84d6-9eb7-1f48e7351d0f.png)

### 論理データモデルへの変換
次に概念データモデルを論理データモデルに変換します。基本的には1つのEntityが1つの表に対応します。しかし、多対多のRelationshipが存在すると、そのままでは関係モデルとして取り扱うことができません。多対多の関係を解消するためには、多対多の関係を持つEntityの間に新たなEntity（連関Entity）を追加し、多対多の関係を1対多、多対1の関係に置き換えます。先ほどの図における商品と売上の関係であれば、例えば売上明細というEntityを追加して多対多の関係を解消します。1件の売上明細には1つの商品が含まれ、1件の売上明細はいずれか1つの売上に含まれるので、商品と売上明細の関係が1対多、売上明細と売上の関係が多対1となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897889/4f8affb4-4470-6985-7ee8-52efc33d6595.png)

多対多の関係が解消できたら、各Entityが保持する詳細な属性、属性のデータ型やデータ長などを明確にしていきます。続いて、各Entityが冗長なデータを保持しないように正規化を行い、論理データモデルが完成します。正規化の詳細については、次回に説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897889/41cbbf1a-b9ad-1edb-39f4-a0eb829bac52.png)

## 次回
[テーブル構造を考える②（正規化編)](https://qiita.com/ruuuuu/items/52f9653b159d41f301c8)
Laravelをphp-fpmからOctaneに移行したらAPCuキャッシュが機能しなくなった

## 概要

LaravelアプリをNginxと[php-fpm](https://www.php.net/manual/ja/install.fpm.php)で繋げた設定をDocker化して開発していた環境をOctane(OpenSwoole)に移行したときに起きた問題をご紹介します。

移行内容などは、以下の各記事などから前提知識を得てからご覧ください。

https://0115765.com/archives/7350#google_vignette

https://tech-blog.optim.co.jp/entry/2023/07/24/100000

https://developers.cyberagent.co.jp/blog/archives/35832/

## 問題

Laravelを`FROM php:8.2.0-fpm`指定したイメージでコンテナを作り、Nginxのコンテナから[ngx_http_fastcgi_module](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)の設定で疎通できるようにDocker環境を作っていました。

そこでOctaneに移行してNginxとはリバースプロキシでの疎通に変わったことにより、[APCu](https://www.php.net/manual/ja/book.apcu.php)を指定したLaravel Cacheで保存も取得もできない問題が起きました。

https://blog.capilano-fw.com/?p=1344

APCuの設定は、PHPコンテナを作るDockerfileに`RUN pecl install apcu && docker-php-ext-enable apcu`を記述してLaravel Cacheで`apc`を指定すれば使用できます。

以下のサンプルでも確認できます。

```php:app/Service/RandomNumberService.php
<?php
namespace App\Service;

class RandomNumberService
{
    protected $number;

    public function __construct()
    {
        $this->number = mt_rand(1, 10000);
    }

    public function getNumber() :int
    {
        return $this->number;
    }    
}

```

```php:app/Http/Controllers/SampleController.php
<?php

namespace App\Http\Controllers;

use App\Service\RandomNumberService;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cache;

class SampleController extends Controller
{
    public function __construct(
        private RandomNumberService $service
    ){}

    public function index(): Response
    {
        Cache::store('apc')->forever("getNumber", $this->service->getNumber());
        $num = Cache::store('apc')->get("getNumber", "-1");
        return response('Number:' . $num, Response::HTTP_OK);
    }
}
```

🔽php-fpm環境
![スクリーンショット 2024-10-06 19.21.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82601/aeaf7565-9ed5-c7a5-82a9-79882a41833f.png)

🔽Octane環境
![スクリーンショット 2024-10-06 19.28.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82601/230fe7e5-9a32-11b1-c03f-547df820ab91.png)


## 対策

https://www.php.net/manual/ja/apcu.configuration.php#ini.apcu.enable-cli

> この設定はほとんどの場合、テストかデバッグに使います。 これを設定すると、CLI版PHPでAPCが有効になります。 通常の状態では、CLI リクエストのたびにAPCキャッシュを生成し、 収集し、破棄するのは望ましくありません。しかし、テストシナリオによっては、 CLI版のPHPでAPCを簡単に有効に出来た方が便利な場合があります。

`apc.enable_cli=1`をiniファイルにセットするようにDockerfileを調整したところOctane環境でも`Cache::store('apc')`でキャッシュ機能が正常化しました。

では、なぜCLI有効で正常化したのか調査したところ、Octane環境のSwooleやRoadRunnerなどはプロセス化されたワーカー内部からPHPをCLIで動いているようで、[Debugbar for Laravel](https://github.com/barryvdh/laravel-debugbar)でログを確認するとphp-fpm環境では`"interface"："fpm-fcgi"`となり、Octane環境は`"interface"："cli"`と出力されてました。

また採用したOpenSwooleのDockerに関する設定の公式ドキュメントで`FROM php:8.2.0-cli`を指定されていることからAPCuを利用するにはCLI有効にする必要（RoadRunnerも同じく）がありました。

https://openswoole.com/docs/get-started/try-docker

## まとめ

APCuを何となくで使っていたらハマってしまった罠でした笑汗
Metasequoia4用gpbエクスポートプラグインを作ってみた

# 概要

Metasequoia は日本産の3Dモデリングソフトです。
この Metasequoia 4 用の gpb エクスポートプラグインを作ってみました。gpb ファイルはプログラミング言語 Hot Soup Processor 3.6 のhgimg4 で3Dモデルファイルとして採用されているファイル形式です。

アニメーションには対応しておらず
主に小物などを作成を意図しています。

本エクスポートプラグインの説明は以下にも記載しています。
https://github.com/hta393939/metaseqtry/tree/main/mqsdk487/mqsdk/exportgpb

# インストール

https://github.com/hta393939/metaseqtry/releases/

上記ページから最新の gpbexport.x.x.x.zip をダウンロードしてください。
例えば gpbexport.0.10.2.zip のようになります。
その後、Metasequoia 4 のGUIからインストールします。
メニューから「ヘルプ」→「プラグインについて」をクリックします。 「プラグインについて」ダイアログの「インストール」をクリックします。 さきほどダウンロードした exportgpb.x.x.x.zip ファイルを選択して 「開く」をクリックします。 リストに Export HSP GPB(*.gpb) が追加されたら成功です。

# 使い方
モデリングをした後、メニューの「ファイル」「名前をつけて保存」で
「ファイルの種類」で「HSP GPB(*.gpb)」を選択してください。
その後「保存」をクリックします。


# 制限事項

- 頂点カラーには非対応です。
- 材質拡散光以外には非対応です。
- 半角英数以外を含む材質名には対応していません。
- 半角英数以外を含むテクスチャファイル名には対応していません。
- 半角英数以外の文字を含むボーン名には対応していません。重みは4ボーンまでです。
- png以外のテクスチャファイルに対応していません。
- アニメーションに対応していません。


# リンク

Metasequoia 公式
https://www.metaseq.net/jp/

Hot Soup Processor 3.6
https://hsp.tv/
[Cost Management] 工開発規模・工数の見積手法

# 一覧
|||
|:--|:--|
|標準タスク法<br>積上法|作業項目を見積もり可能な``単位作業``まで分解し、``標準工数をボトムアップ的に積み上げて``全体の工数を見積もる方法|
|COCOMO|Constructive Cost Model<br>``ソフトウェアの規模``から、開発工数および開発期間を見積もる方法<br>``プログラム行数``×``努力係数``(信頼性、複雑性、開発要因の能力などのコスト要因)|
|ファンクションポイント法<br>FP法|システムの``外部仕様``からそのシステムの機能の量を算定し、開発規模を見積もる方法<br>``ファンクションタイプ``×``補正係数``(ソフトウェアの複雑さや特性)|
|||



# 参考リンク
- [R3S9_PM](https://www.ap-siken.com/kakomon/03_haru/pm09.html)
AWS CodeDeployでのデプロイ失敗: セキュリティトークンの期限切れ問題と解決策

## AWS CodeDeploy のエラーと解決策：セキュリティトークンの期限切れ問題

AWS CodeDeploy を試していた際、最初のステップですら実行されず、AWS コンソールには「デプロイできなかった」と表示されていました。問題の詳細を確認するために、EC2 インスタンスにログインして `codedeploy-agent` のログを確認しました。

### エラーログ
以下のエラーメッセージが `codedeploy-agent` のログに繰り返し出力されていました。

```
$ tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log
2024-10-05T10:59:04 ERROR [codedeploy-agent(19926)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Error polling for host commands: Aws::CodeDeployCommand::Errors::UnrecognizedClientException - The security token included in the request is invalid.
```

どうやら AWS にアクセスするためのセキュリティトークンが無効になっているようです。続いて、以下のエラーも発生していました。

```
2024-10-05T16:50:06 INFO  [codedeploy-agent(19926)]: [Aws::CodeDeployCommand::Client 400 2.16029 3 retries] poll_host_command(host_identifier:"arn:aws:ec2:ap-northeast-1:326141484871:instance/i-0f73b74490d872733") Aws::CodeDeployCommand::Errors::ExpiredTokenException The security token included in the request is expired
```

このエラーは、セキュリティトークンの期限が切れていたことを示しています。

### 試した解決策
以下の対応を試しました。

1. **codedeploy-agent の再インストール**
    - エラーメッセージは変わらず、問題は解決しませんでした。

2. **IAM ロールのデタッチと再アタッチ**
    - この手順を実施したところ、エラーメッセージが消え、デプロイが成功しました。

### 考察
正確な原因は特定できませんでしたが、EC2 インスタンス上で `codedeploy-agent` が利用するセキュリティトークンが不正（または期限切れ）となった場合、IAM ロールのデタッチと再アタッチが有効な解決策になる可能性があります。同様の問題に直面した際には、この方法を試してみると良いかもしれません。
【実験】WireGuardでローカルNICと同じIPを振るとどうなる？【OpenWrt】

# 結論
何事もなく普通につながる(拠点間通信もOK)

# 想定環境
- 拠点A
    - LAN:`10.0.0.1/24`
    - WireGuard:`10.0.0.1/32`
        - Peer:拠点B(`10.0.1.0/24`)
- 拠点B
    - LAN:`10.0.1.1/24`
    - WireGuard:`10.0.1.1/32`
        - Peer:拠点A(`10.0.0.0/24`)

# 感想
WireGuard用にセグメント切ってましたが、被せるとどうなるのかな？と思って試してみました。
ルート重複もしないし普通に考えてそらそうよって感じですね。
ファイアウォールについてはゾーン区別していれば問題ありませんでした。
[JavaScript]イベントループについて

LinkedInを見ていたら以下のような場合、どういう順番でログが出力されるのかについて問題を出しているポストがあった。
普段はvueを使っているのでvueのライフサイクルはある程度わかっているつもりだったが、JavaScriptのライフサイクルは全然わからなかった。

``` js
console.log("A");

setTimeout(() => {
    console.log("B");
}, 0);

Promise.resolve().then(() => {
    console.log("C");
}).then(() => {
    console.log("D");
});

console.log("E");
```

答えから先に言うと、上の場合は`AECDB`の順番で出力される。

## jsのライフサイクル
まず、jsのイベントループを理解するにあたって、`コールスタック`という概念が核になる。

コールスタックとは、プログラムの実行順序を管理するためのデータ構造である。

スタックは「後入先出」（LIFO: Last In, First Out）の原則で動作し、最後に追加された処理が最初に実行される。

コールスタックは、関数が呼び出されるたびに、その関数の情報をスタックの一番上に追加しする。関数の実行が完了すると、その情報はスタックから取り除かれていく。

## タスクの種類
そこで、jsでは非同期処理が可能であるため、タスクごとに実行されるタイミングを調整する必要がある。そのため、タスクは以下のような種類で分けられる。

1. 同期タスク：即時実行
2. マイクロタスク：`Promise`、`queueMicrotask()`、`MutationObserver`等
3. マクロタスク：`setTimeout`、`setInterval`、`requestAnimationFrame`、`I/O操作`等

## 実行順序

同期タスク → マイクロタスク → マクロタスク

実はコールスタック以外にもjsにはコールバックキューとマイクロキューというものがある。

コールバックキュー（タスクキューとも呼ばれる） = マクロタスク用
マイクロキュー = マイクロタスク用

だと理解するとわかりやすい。

以下のような流れで順番通りに実行されるようになっている。

1. スクリプトを読み込む
2. 同期タスクであれば実行する
3. マクロタスクだったらコールバックキューに、マイクロだったらマイクロキューに入れる（実行はしない）
4. スクリプトが終わるとマイクロキューのタスクを実行する
5. マイクロキューが終わるとコールバックキューを実行する


## 具体例
ということで、自分なりにタスクを並べて、実行される順番を考えてみた。

``` js
console.log('1. スクリプトスタート');

setTimeout(() => console.log('2. setTimeout 0'), 0);

Promise.resolve().then(() => console.log('3. Promise.resolve'));

queueMicrotask(() => console.log('4. queueMicrotask'));

Promise.resolve().then(() => {
    console.log('5. Nested Promise.resolve');
    setTimeout(() => console.log('6. Nested setTimeout'), 0);
});

async function asyncFunction() {
    console.log('7. async関数内');
    await Promise.resolve();
    console.log('8. await後');
}

asyncFunction();

requestAnimationFrame(() => console.log('9. requestAnimationFrame'));

console.log('10. スクリプトおわり');

// 出力順番:

// 同期タスク
// 1. スクリプトスタート
// 10. スクリプトおわり

// マイクロタスク
// 3. Promise.resolve
// 4. queueMicrotask
// 5. Nested Promise.resolve
// 7. async関数内
// 8. await後

// マクロタスク
// 2. setTimeout 0
// 6. Nested setTimeout
// 9. requestAnimationFrame
```

## おわりに
vueのライフサイクルよりこっちを先に勉強するべきだった。
今まで非同期処理がどうなっていたかも知らずにやってきたとは...
ポートフォワーディングが意味わからんので理解したい(Teraterm とかで SSH で踏み台経由するやつ)


今回理解したのはローカルポートフォワーディングと呼ばれるもの。

# 準備

## 構図はこんな感じ
自分の PC → 踏み台 → サーバーという形でつなぐ。

※つなぐ（繋ぐ）。アクセスする、接続する、の意味。

![20241006_195247.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/a7a76350-f9f1-eb58-a7b6-5c5b82cbba22.jpeg)

## 問題: 踏み台からサーバーにつなぐところがだるい
PC は Windows で Teraterm が使えるけど、踏み台は Linux で Teraterm は使えない。SSH コマンドとか使うのだるい。

**PC から直接サーバーにつなぐ感じで使えたら便利** なのでそうしたい。

# どうやる？
Ans: **ポートフォワーディング（ポート転送）** を使う。

長いし、わかりにくいので、以下「ポート転送」を使う。

## 1: 踏み台に転送してもらえばいい、と考える
踏み台につないだ後、さらにサーバーにつなぐ部分も自分でやるのがだるいわけだ。

そこを踏み台に代行してもらえないだろううか？

図にすると、以下のような感じ。

![20241006_195715.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/6c4008eb-3388-dab3-a8a6-9a7698c55081.jpeg)

自分としては踏み台につなぐところまではやる。その先は踏み台さん、あなたがやってくれませんか？とする。

## 2: そんなことできるの？
できる。

踏み台には sshd というデーモン（常駐プログラム）がいる。こいつはそもそも SSH 接続を司る機能だが、**転送機能** も持っている。

## 3: 転送の仕組み
sshd は「sshd に届いた **ポート xx** の分を、**あるサーバー** の **ポート yy** に転送する」という形で転送を担う。必要なパラメーターは以下の3つ。

- 1: sshd に届く側のポートxx
- 2: あるサーバーの接続先（IPアドレスとか）
- 3: 同上、そのサーバーのポートyy

すなわち図にすると、以下のようになる。

![20241006_200230.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/e454105e-36f8-34d3-e892-7975822ce368.jpeg)

## 4: あとは転送を依頼すればいい
あとは sshd に転送設定を教えればいい。これは SSH クライアント側で行う。Teraterm の場合は、以下のようになる。

![20241006_200424.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/b1573a7c-56d3-9b44-46b2-d3689127b8d2.jpeg)

ややこしいが、上記の設定画面では踏み台の接続先は記載していない。踏み台の接続先はこっちでやる。

![20241006_200851.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/66aa2b7c-74b6-86fc-1fe8-c4f2e8e0b3eb.jpeg)

# ポート転送完了！
これでポート転送が行えるようになる。

自分は Teraterm で踏み台の xx につなぐだけで、実際にはサーバーの yy にまでつながってくれる。

内部的には、踏み台で動いている sshd が（Teraterm からの指定に従い）転送を行ってくれている。
イラストを自動生成してくれる絵日記アプリ

# 絵日記のようなアルバムアプリを作りたい
スマホのアルバムを見返していて、こんなことを思うことはありませんか？

:::note warn
・表情を作るのが苦手でその時の楽しさをうまく思い出に残せない。
・旅行に行ったのに自撮りだと毎回構図が同じ。
:::

＜イメージ＞
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775986/0bbcb697-c0d8-def6-a5b6-f11b6cee916b.jpeg" width=50%>

私は結構あります…

その時の雰囲気や自然な表情をそのままの形で残したい！
そこで絵日記のようにイラストという形で思い出を残せるアルバムアプリ「おもいで絵日記」を作りました。

＜使用イメージ＞
夏休みの思い出を絵日記に残すというイメージで作成したデモ動画です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775986/ce58c346-880d-bcf9-430a-6c204f59cfe0.gif" width=80%>


# 使用環境
・Messaging API(LINE)
・OpenAI API(ChatGPT)
・Make
・Googleスプレッドシート


# アイデア
①．LINE Botにひとこと日記の要領で思い出を投稿する。
②．日記の内容からAIでそのシーンをイラスト化してアルバムに残す。
絵を描くのがあまり得意じゃないという方でも手軽に絵日記のように自分の好きな雰囲気のイラストを残せようにしたい。

# 実装イメージ
今回はアプリ作成にMakeというノーコード開発ツールを使用しました。

:::note
ポイント
・LINE Botからイラスト作成に必要な情報を取得
・OpenAI APIに情報を渡してイラストを生成
・情報はGoogleスプレッドシートに集約
:::

Makeで作成したツールのフロー図
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775986/249ac8cf-70dc-ebba-d6fa-5c5b4b47789b.png" width=100%>

作成したイラストはWebアプリなどで閲覧しやすいようにGoogleスプレッドシートにURLを書き出すようにしました。デモ動画では閲覧用のアルバムをCode PenでWebアプリとして作り、LINE Botのリッチメニューから飛べるようにました。

# こだわりポイント
Googleスプレッドシートに情報を集約することで、処理フローが一本（シンプル）になるように工夫しました。
B列：LINE Botから入力した情報
C列：作成したイラストのURL
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775986/a91271b1-b66f-aaa9-e250-faaf38069019.png" width=100%>

ChatGPTに「イラストの雰囲気」を付けたした情報を渡すようにすることでイラストを自分好みの雰囲気で作成できるようにしました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775986/ec916acf-86df-8e17-a1d2-a67b075dc1b2.png" width=50%>

※デモ動画では「絵日記っぽく、温かく楽しそうな雰囲気」を表現できるようにプロンプトに渡す情報を決めました。

# 参考資料
https://developers.line.biz/ja/docs/

https://www.syou-getsu.biz/lise/make/make_guide02

https://qiita.com/watanabe-tsubasa/items/8342595d641143b780f7
【Android】JetpackComposeでテキストを常にスクロールさせる【Kotlin】

# はじめに
今回は引き受けている仕事の中でなかなかJetpackComposeに触れないでいる中、自分のインプットの中だけでもなるべく触ろうと思い立ったが、何から触ろうかと思ったので、自分の興味のあるアニメーション関係からきっかけを作ろうと色々触っている中で見つけたものを紹介していこうと思います。
今回記事にて紹介するものは　**basicMarquee()** です。

タイトルではテキストをスクロールと言いましたが、公式には
>任意のコンポーザブルに basicMarquee 修飾子を適用すると、アニメーション化されたスクロール効果を生成できます。

とあるので、TextView以外でも使えるっぽいです。

# 使い方

```
@Composable
fun TextMarquee() {
    Column(Modifier.width(400.dp)) {
        Text(
            "テキスト",
            modifier = Modifier.basicMarquee()
        )
    }
}
```

基本的にはModifierにbasicMarquee()を追加して、必要なパラメータを追加するだけです。

# パワメータ


|パラメータ名|型|意味|
|:---|:---:|:--|
|iterations|Int|繰り返す回数 Int.MAX_VALUEなら永久に繰り返され、0を指定するとアニメーションを無効にできる|
|animationMode|MarqueeAnimationMode |アニメーションの開始を自動でするImmediatelyか、そのViewにフォーカスが向いている時にアニメーションをするWhileFocused|
|repeatDelayMillis|Int|反復を開始するまでに待機する時間(ミリ秒)|
|initialDelayMillis|Int|アニメーションを開始するまでの時間(ミリ秒)|
|spacing|Int|アニメーション終わりのスペースの大きさ|
|velocity|Dp|スクロールするアニメーションの速さ|





# 参考

https://developer.android.com/reference/kotlin/androidx/compose/foundation/package-summary#(androidx.compose.ui.Modifier).basicMarquee(kotlin.Int,androidx.compose.foundation.MarqueeAnimationMode,kotlin.Int,kotlin.Int,androidx.compose.foundation.MarqueeSpacing,androidx.compose.ui.unit.Dp)


https://developer.android.com/develop/ui/compose/text/style-text?hl=ja#apply-marquee
GASでGoogle Drive上のファイルをコピーする方法

## 機能概要
このGoogle Apps Scriptの関数 `createFilesFromTemplate()` は、テンプレートファイル(xls)を複製し、各社員ごとの情報に基づいて個別のファイルをGoogleドライブ上の指定されたフォルダに作成するスクリプトです。
※ 例えば勤怠を入力するファイルがあったら、それにファイル名を付けて複製するだけの機能です。

### 主な機能:
※テンプレートファイル(xls)は事前に作成しておく必要があります。
1. **テンプレートファイルの取得**:
   - Googleドライブ上のテンプレートファイル（Excelファイル）をコピー元として使用します。
   - テンプレートファイルのID（`fileId`）を指定してファイルを取得します。

2. **社員ごとのファイル生成**:
   - 社員情報（会社名、氏名、メールアドレス）をリストとして保持し、社員ごとに異なるファイル名を生成します。メアドは現在は使ってないですが、権限付与が必要になったら使う予定
   - 生成されるファイル名の形式は、`会社名_氏名.xls` です。

3. **ファイルの複製と保存**:
   - テンプレートファイルを複製し、社員ごとのファイル名で指定されたフォルダに保存します。
   - スクリプトでは `DriveApp` を使用して、コピー先のフォルダ（`destinationFolderId`）を指定して保存します。




### コピー元のファイルの修正
コピー元のファイルの中で日付とか直したい箇所があれば修正しておく。

### gasでコード作成
何かスプレッドシート用意してgasを作ろう
拡張機能->apps script

```js
function createFilesFromTemplate() {
  // テンプレートファイルのID（GoogleドライブのURLから取得可能）
  // https://docs.google.com/spreadsheets/d/1fX9yTm4bnpK8FBOREG_m6kz6cKd9mfl6/edit?gid=1381060538#gid=1381060538
  var fileId = '1fX9yTm4bnpK8FBOREG_m6kz6cKd9mfl6';  // コピー元のファイルID
  // コピー先のフォルダID（GoogleドライブのURLから取得可能）
  // https://drive.google.com/drive/folders/1TueBj-LtKvcUE-jNpwDGXGzqY8SY4lQ5
  var destinationFolderId = '1TueBj-LtKvcUE-jNpwDGXGzqY8SY4lQ5'; // コピー先のフォルダID
  
  // 社員情報のリスト（会社名, 氏名, email）
  var employees = [
    { companyName: '会社A', name: '山田太郎', email: 'taro.yamada@example.com' },
    { companyName: '会社B', name: '佐藤花子', email: 'hanako.sato@example.com' },
    { companyName: '会社C', name: '鈴木次郎', email: 'jiro.suzuki@example.com' },
    // ここに他の社員情報を追加
  ];

  // コピー先のフォルダを取得
  var destinationFolder = DriveApp.getFolderById(destinationFolderId);
  
  // 各社員ごとにファイルを作成
  employees.forEach(function(employee) {
    // ファイル名を生成
    var newFileName = employee.companyName + "_" + employee.name + ".xls";
    
    // テンプレートファイルをコピー
    var copiedFile = DriveApp.getFileById(fileId).makeCopy(newFileName, destinationFolder);
    
    // ログに結果を記録
    Logger.log('ファイル作成完了: ' + newFileName);
  });
}
```
### 実行
- 社員情報`employees`に変更があれば修正し、実行する。
- 実行すると、destinationFolderIdに指定したグーグルドライブ上にファイルが作成されているはずです。


### TODO
コピーする際にファイルの中を加工しようと思ったがハードルが高かった。
扱っているのがxlsだが、ブラウザで開くとスプレッドシートに変換されている。xlsで修正を加えることができなかった。修正するにはgoogle drive apiが必要と出てきて、認証が面倒そうだったのでやめた。
xlsではなく、最初からスプレッドシートを使っているなら面倒なことはないのかもしれない
AWS CLF02を取得した時の話。【未経験】2024年7月上旬

# はじめに
　AWSのクラウドサービスを使って業務で使用したいと思ってはいたものの手探りすぎてまともな知識もないまま使用するのはどうかと思い、学習する1つの目的としてCLFを受験することにしました。

 AWSについて事前に知識はほぼなく、業務でWindows Server, SQL Server, 自社ソフトウェアの環境移設作業を便利にできるものがないかと探していたところクラウドで実装できそうだとなったことがキッカケになります。
 # 学習
　テキストを買ってまずは1週読み、2週目で1週目の演習問題で間違えたサービスなどじっくりと読みました。極力お金をかけず合格したかったのでWEBやスマホの無料の問題ばかりを解いていました。ふむふむ、そういう機能が...などと順調に学習していたつもりでしたが、なぜか前日に急に不安になりUDEMYで有料の講義を1つ購入して模擬試験を解くことにしました。
#### そこでトラブル発生
問題を解いているとなんか知らないサービスめっちゃ多いし、正答率40%...やはり試験はまだ自分には難しいのか。。と思いながら慌てて試験について調べなおしたところはじめに購入して学習していたテキストがCLF-02版ではありませんでした。
※2024/10現在はCLF-02版が出版されております。
とはいえ試験は明日なのでと、ひたすら問題を解き解説をじっくり読み9割正解できるまで繰り返しました。　結果は**712点**でギリギリの合格でした。
# 最後に
あまり私のような人はいないと思いますが試験のバージョンだったりテキストが古すぎたりには注意しましょう。この後挑戦予定のAWS SAA03のテキストは出版日を見て購入しました。笑
ファイルシステムが壊れた（本当は壊れてなかった）のを直した

# tldr
[重複除去](https://learn.microsoft.com/ja-jp/windows-server/storage/data-deduplication/overview)を構成したディスクを別環境に持っていくときは移行先でも重複除去をインストールしておかないとデータが読めないよ。

# 障害内容
## 環境
### OS
windows server 2019 → 2022</dd>

### ストレージ構成
<dl>
  <dt>OS</dt>
  <dd>SSD</dd>
  <dt>データ</dt>
  <dd>HDD複数台 記憶域プールを構成<br />プール内に複数のボリュームを作成<br />問題の生じたボリュームはReFSでフォーマットされ、重複除去を構成していた
</dl>

## 経緯
サーバーのハードウエアトラブルで故障したため、ハードウエアをリプレイスし再構築することにした。
OSをクリーンインストールし、Windows server 2019 → 2022 にアップグレードした。
データディスクは旧環境で使用していた物を新環境にそのまま再接続した。
記憶域プールは正常に動作し、プール内のボリュームは全て正常にマウントされた。
しかし、1台のみファイルが正常に開けない問題が生じた。

## 事象
- 記憶域プール内にある複数のボリュームの内1台のみデータが読み取れない事象が発生した。
- 数KB程度の小さいファイルは問題なく開けるがそれ以上のサイズのほとんどのファイルが開けない。
- ディレクトリ構造は正しく表示される。
- ファイルのプロパティを見るとサイズは正しく表示されるが、ディスク上のサイズが0バイトとなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153956/f3c57b82-aa1d-1487-fbd7-f99be98ad9ae.png)
- ファイルをコピーしようとすると「予期しないエラーのため、ファイルをコピーできません。」「エラー 0x80070780: ファイルにアクセスできません。」が発生する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153956/bc48e9e3-bac8-5b77-b604-48b576a80a57.png)
- イベントログ等に不審な点は無し
- 書き込みや移行後に書き込んだファイルの読み取りに問題は無し

## 試した施策
### ディスクイメージの作成・退避
disk2vhd での問題の生じたディスクのイメージ化。読み取り専用状態での退避。
結果的に壊れてた訳ではなかったので意味は無かったですが、本当に壊れてる可能性を考慮すれば無駄では無かったかと思います。
修復を試している間に事態が悪化して取り返しの付かないことになるのを防げます。

### 作成したイメージを元の環境のコピー環境にマウント
元の2019の環境をp2vで残していたので作成したイメージを仮想環境にマウントしましたが、RAWと表示され開けませんでした。
こちらは今のところ原因不明のままです。
問題が生じなければこの環境には重複除去が入っていたのでファイルも開けたはずなのですが、結果的にファイルシステム自体破損しているとの疑念を深める結果となってしまいました。

### ReFSUtil
[ReFSUtil](https://learn.microsoft.com/ja-jp/windows-server/administration/windows-commands/refsutil) とはReFS用のボリューム診断、修復ツールです。
破損したReFSボリューム内のファイルをサルベージすることができます。
サルベージを実施したところ破損した元と同じサイズのファイルが出てきましたが、開いたところ内容が破損していました。
サルベージした結果、System Volume Information内にやたらと大容量のファイルがたくさんあったのは原因に気づく手がかりの一つにはなったかもしれません。

## 原因
移行先で重複除去機能をインストールしていなかった

## 対処
重複除去機能をインストールし、OS再起動で解決。

# あとがき
些細なミスではありますが、特に決め手となるような情報は少なく、重複除去を設定したことすら忘れて居たため解決まで時間がかかってしまった。
今回は記憶域プール+ReFS環境で発生しましたが、通常のドライブやNTFSでも同じ事象が発生することを確認しました。

同様のトラブルに遭遇した人の助けとなるように記録を残します。
[DWH]データウェアハウスの活用

# 一覧
|||
|:--|:--|
|データウェアハウス<br>DWH|企業活動で得られた大量のデータを整理・統合して蓄積しておき、意思決定支援などに使用するデータベース|
|ETL|Extaract / Transformation / Load<br>基幹系データベースから抽出、変換、DWHへのロード|
|OLAP|Online Analyytical Processing<br>多次元データをさまざまな視点から対話的に分析する処理形態、または技術|
|データマイニング|大量のデータから統計的・数学的手法を用いて、データの法則性や因果関係を見つけ出す手法|




# 参考リンク
- [R3S2_PM](https://www.ap-siken.com/kakomon/03_haru/pm02.html)
スタックとキューと FIFO と LIFO を理解する


概要とイメージとかんたんな用途だけ。コードは無し。

# スタックとキューはデータ構造の一種

## スタック
**スタック（Stack）** は、一段ずつ積み上げて保存する構造で、取り出すときは上から取り出す。

こんな入れ物があったとする。

```
  |
  V

|   |
|   |
+---+
```

A, B, C の順で入れたとすると、以下のようになる。

```
| C |
| B |
| A |
+---+
```

ここから取り出すときは **上から取り出す**。なので「何を取り出すか」なんて言わない。「何回取り出すか」だけだ。

たとえば 2 回取り出したら、こうなる。

```

 1回目に取り出したもの: C
 2回目に取り出したもの: B

|   |
|   |
| A |
+---+
```

## スタックの用途
たとえば履歴管理に使われる。

皆さんが今見ているブラウザの戻る・進む動作も、スタックで実現されている。

たとえば以下の行動をしたとして、

- 1: X(Twitter) のホーム画面を開く
- 2: タイムラインに流れていた、兎田ぺこらのツイートの詳細を開く
- 3: YouTube 動画リンクされてるので、そっちを開く
- 4: 関連動画でこんこよのライブが始まっていたので、そっちを開く

その後、一回だけ戻る操作をしたとする。これはスタックで表現すると、以下のようになる。

```

          Watching   Watching
            [4]        [3]


|   |      | 3 |      |   |
|   | ---> | 2 | ---> | 2 |
|   |      | 1 |      | 1 |
+---+      +---+      +---+
```

要は、

- 新しいページを開いたら、さっき見ていたページをスタックに入れる
- 戻るボタンを押したら、スタックから一つ取り出してそれを開く

という操作をしている。

## キュー
**キュー（Queue）** は、入口から一個ずつ詰めて保存する構造で、出すときは出口から出す。

こんな入れ物、というか筒があったとする。

```
      ------
---> 
      ------
```

A, B, C の順で入れたとすると、以下のようになる。

```
      ------
--->   C B A
      ------
```

ここから取り出すときは **出口から取り出す**。スタックと同様、「何を取り出すか」なんて言わない。「何回取り出すか」だけだ。

たとえば 2 回取り出したら、こうなる。

```
 1回目に取り出したもの: A
 2回目に取り出したもの: B

      ------
--->       C
      ------
```

## キューの用途
現実では **待ち列** としてよく使われる。実際は急患を優先したり、順番を抜かす悪い人がいたりするが、考え方自体は非常に身近であり、改めて説明されるまでもないだろう。

IT では、特定のプログラムが処理を受け取る受信箱として使うことが多い。特に複数のプログラムやサーバーが連携しているような複雑なシステムでは、「受信箱にリクエストが来たら処理しますわ」「受信箱は 10 秒ごとにチェックしますわ」の形を取ることが多い。これだと受信箱を見るだけでいいので管理がシンプルになる（※1）。この受信箱に使われるのがキューである。

※1 ただし誰がいつ何を入れて、といった取り決めはちゃんと考えないといけなくて、その辺は複雑になる。

このとき、私たちが普段使うメールやチャットのように読み飛ばしたりはしない。来たものから順に処理する。**その方が単純だし、漏れもないし、わかりやすいから使い勝手が良い**。もし、これで問題がおきたとしたら、キューに入れる量か、取り出して処理する側の能力がおかしいのでそっちを何とかすればいい。キューのせいじゃない。キューの部分（受信箱の部分）は至ってシンプルだ。

# FIFO と LIFO は正直無視していい
実用上は困らないし、読み飛ばしても困ることは無いと思う。

一応、解説しておくと、キューのように先に入れたもの（First In）が先に出てくる（Last Out）構造を **FIFO** といい、スタックのように後に入れたもの（Last In）が先に出てくるものを **LIFO** という。

後ろの FO の部分（First Out、先に出る）が同じというネーミング。

# あー、あとは操作名の話
スタックに入れることをプッシュ（Push）、スタックから取り出すことをポップ（Pop）という。

キューに入れることエンキュー（Enqueue）、キューから取り出すことをデキュー（Dequeue）という。
libreoffice の TeX 数式で日本語

libreoffice の TeX 数式機能、美しくてよいのだけれど、日本語を埋め込めないのが残念。なので、ちょっとハックして、対処してみた。
かなりアドホックな対処なので、正しい方法を知っている人がいたら、教えてほしい。

# 修正箇所
* 環境： 
    * linux (Ubuntu 20.04.6 LTS)
    * LibreOffice 6.4.7.2 40(Build:2)
    * platex: e-pTeX 3.14159265-p3.8.2-190908-2.6 (utf8.euc) (TeX Live 2019/Debian)
* libreoffice オフィスの個人設定 directory の下の TexMaths に移動。
```
cd ~/.config/libreoffice/4/user/TexMaths
```
* "TexMaths-texm.sh" を以下のように修正。
    * 65 行目付近の `latex` を `platex` に。
    * 72 行目付近の `dvisvgm` の行を以下のように変更
```
dvipdfmx ${filename}.dvi &> ${filename}.dout
pdfcrop ${filename}.pdf ${filename}_.pdf &>> ${filename}.dout
mv ${filename}_.pdf ${filename}.pdf
dvisvgm -n1 -P -e ${filename}.pdf &> ${filename}.dat
```
* 上記の変更の patch は以下の通り。
```
*** TexMaths-texm.sh.org	2024-10-06 16:39:31.274347783 +0900
--- TexMaths-texm.sh	2024-10-06 18:04:28.476477157 +0900
*************** fi
*** 62,75 ****
  rm ${filename}.{dvi,out,bsl,dat,log,aux,png,svg} &> /dev/null
  
  # Creation of the DVI file
! latex -shell-escape -interaction=nonstopmode ${filename}.tex  > ${filename}.out
  
  # Conversion of the DVI file to a SVG image
  if [ -f ${filename}.dvi ]
  then
  if [ "${ext}" = "svg" ]
  then
!    dvisvgm -n1 ${filename}.dvi &> ${filename}.dat
  fi
  fi
  
--- 62,78 ----
  rm ${filename}.{dvi,out,bsl,dat,log,aux,png,svg} &> /dev/null
  
  # Creation of the DVI file
! platex -shell-escape -interaction=nonstopmode ${filename}.tex  > ${filename}.out
  
  # Conversion of the DVI file to a SVG image
  if [ -f ${filename}.dvi ]
  then
  if [ "${ext}" = "svg" ]
  then
!    dvipdfmx ${filename}.dvi &> ${filename}.dout
!    pdfcrop ${filename}.pdf ${filename}_.pdf &>> ${filename}.dout
!    mv ${filename}_.pdf ${filename}.pdf
!    dvisvgm -n1 -P -e ${filename}.pdf &> ${filename}.dat
  fi
  fi
  
```

## 苦労した点など
* 日本語が出なかったのは、`latex`が日本語に対応してなかったのと、`dvisvgm` が日本語フォントにうまく対応してくれていないため。
* `platex` の出力をちゃんと表示するためには、やはり `dvipdfmx` に頼らざる得ない。
* しかし、`dvipdfmx` はちゃんとした boundary-box を含めていない。
* なので、`pdfcrop` で文字のあるところだけ切り出す。
* 最終的な出力ファイルのファイル名が `${filename}.svg` と決め打ちのようなので、それに会うようにファイル名の変更などしている。


あまりテストしてないので、不具合があれば、コメントなどしてみてください。時間があれば、対応するかもしれません。
YAPC::Hakodate 2024に参加！B1がカンファレンスに初参加した感想

# 注意事項
筆者は初の執筆なので冗長言い回しや、わかりにくい表現が多分に含まれます。温かい目で読んでいただけると幸いです。
また、技術的な話は一切含まれません。感想のみとなっております。
言い回しや、もっと深い描写が欲しい部分などコメントいただけると嬉しいです。
# YAPC::Hakodate 2024概要
さてYAPCに参加してきたわけですが、そもどんなイベントなのかというと…
「YAPCはYet Another Perl Conferenceの略で、Perlを軸としたITに関わる全ての人のためのカンファレンスです。 Perlだけにとどまらない技術者たちが、好きな技術の話をし交流するカンファレンスで、技術者であれば誰でも楽しめるお祭りです！」
というテックカンファレンスです。([webページから引用](https://yapcjapan.org/2024hakodate/))

かくいう僕はPerlを触ったこともない、インターンにも行ったことがない様なぺーぺーエンジニアだったわけですがとても楽しめました！

## 参加した経緯とか
YAPCに参加したきっかけは、大学生の先輩に誘われたことでした。
「こんどYAPCっていうカンファレンスが函館であるんだけど来る?」
##### 「行きます」
っていう感じで即決しました。面白そうだったからね仕方ないね()

B1ということもあり、カンファレンスに行っているB4の先輩がいた事、その人と関わりを持てていたこと、という環境に恵まれていたことが大きかったように思います。

## スペックとか知識的ななにか
YAPCに申し込んだ時点で、
- インターンの参加経験なし
- システム開発の経験なし
- テックカンファレンス参加経験なし

というないない尽くしの状態で行きました。
APに合格していたので、プロジェクトの基本的な流れなどを軽く覚えていたことが、唯一役立ったことだと思います。

## トークを聞いて
### まったくわからん！！！
面白そうな話はしていることはわかります
あの分野のこんなことを言ってるんだろうなと検討がつくときもあります
圧倒的にお話が上手いのでとても聞き心地は良かったです
###### それでいてわからん
トークを聞いて、システム開発の知識が圧倒的に足らないことがわかりました。特に開発環境の改善やLLMをプロダクトに活かす話などは実務(インターンなど)の経験がないと深いところまで理解出来なさそうでしたし、webセキュリティの話は、常に?が頭に浮かんでいました。

ただ、それでも知らない英語3文字の略称や聞いたことのないソフトウェアの名前が出てくるたびにメモして「まだ知らないことがたくさんある！頑張らなくては！」と自分を鼓舞しようとあうる感覚もありました。

## LTとkeynote
### 面白かった！！
ためになるLTや、Perlに関する話など、会場の雰囲気も相まって面白い項目だったなと思います。
ただ惜しくば、Perlの知識があればもっと、俗に言うinteresting的な面白さに昇華したのではないかなと思います。

### そしてkeynote
**本当にすごかった**
moznionさんの話し方が上手で、とても印象に残りました
自分の行ってきたことを中心に、エンジニアに対する考え方や個人技の伸ばし方などためになるお話をたくさんしていただきました。
スライドのミス??もありましたが、それも相まってより色濃く心に残っている部分もあります。

## 懇親会
会場を移して懇親会がありました。
企業の方と話す機会があり、開発体制やインターン、どのような学生を採用したいか、更に自分が行っていることに対してアドバイスを頂けたのでとてもいい経験になりました。
本編でなくても、実際に社会人の方のお話を聞いて自分がやっていることがしっかりと未来に繋がっていることを実感し、より成長したいと思うようになりました。

## 最後に
説明が足りないところや冗長になってしまったところがある中、ここまでご覧いただきありがとうございました!!
今後はこの経験を活かして自分のスキルを磨き、イベントに参加してコミュニティを築き、もっと成長できるように頑張りたいと思えたイベントでした！！！！！！

最後は一番印象に残っている言葉で締めたいと思います。

### 量が質に転化するタイミングはありますっっ！！！
C++での外部ライブラリの置き場所の調査【Windows】

# 前書き
C++の超初心者ですから、かなり間違ったことを書いているかもしれません

当方Windowsユーザーで、普段はPythonやRustを書いています。
こういう言語だと、外部ライブラリを導入するときはパッケージマネージャ(Pythonならpip、Rustならcargo)に頼るのですが、C++は**標準としては**その類のツールが存在しないんですよね。
軽く調べたところ、そういうツールは使わないで、直接ダウンロードしてプロジェクトのディレクトリに置いておく(ヘッダファイルをinclude、so, dll等はlib といったディレクトリを作って置く)か、外部の好きなところに置いて、そのパスを書いた環境変数を用意してビルド時に指定するのが大抵のやり方らしいそうな([参考1](
https://ja.stackoverflow.com/questions/45012/c-%E3%81%A7%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92-include-%E3%81%97%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AF-%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AB%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B%E3%81%AE%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%81%8B), [参考2](https://stackoverflow.com/questions/20925067/best-practice-for-storing-external-libraries-on-windows-qt-project))
ということなので、実際にGithubにあるオープンソースプロジェクトのディレクトリ構造を見て回って調べてみた、という備忘録としての記事です

# オープンソースプロジェクトから見る例

## Raylib

- src/externalフォルダに置いている

## Siv3d

- includeとlibに分け、libに外部dll、includeに自身のライブラリ、include/ThirdPartyに外部ライブラリを置いている
- [直接同梱したくないライブラリはDependenciesに置いている？](https://siv3d.github.io/ja-jp/develop/build/)

## [SFML](https://github.com/SFML/SFML)

- extlibsに置いている
shell コマンド 備忘録

## shellコマンド
### mktemp コマンド
文法：mktemp ファイル名 
ランダムな名前のファイル名を作成する

オプション：-d
ファイルではなく、ディレクトリを作成する。
権限は、mktempを実行時のユーザーの権限から決まる。

### if コマンド　オプション -lt
文法：if [ A -lt B ]; then fi
lt： AがBより小さい場合


### tee
文法：tee ファイル名
コマンドの結果をファイルに出力し、標準出力でも出力を見たい場合に使用する
```shell
tee test.tsv > /dev/null
world
# ctrl + C
cat test.tsv
world
```

### ls ディレクトリ | grep -v 'ファイル名' | rm -rf
lsコマンドで実行した結果をgrepに渡し、渡されたファイルの中に指定したファイル名以外のものを検索する。その結果をrmコマンドに渡し、削除する。

上記のやり方だと成功したが、書きの方法では失敗した。
ls ディレクトリ/* | grep -v 'ファイル名' | rm -rf

アスタリスクを付けた場合、grepに送られるファイル名にはコロンが末尾にある。その状態でrmコマンドまで届く。そのため、そのようなファイルは存在しないため削除されずに処理が終了する。

### function()
function とは、関数。
```shell
#!/bin/bash
# 関数の定義
say_hello () {
    echo "Hello!"
}
# 関数の呼び出し
say_hello
# Hello
```
### 参考
https://qiita.com/wnoguchi/items/2fc3ec11043d139dc6bb
https://qiita.com/kaw/items/034bc4221c4526fe8866
googleを名前に含むCloudStorageは作れない【name value cannot contain "google" or close misspellings, such as "g00gle"】

## はじめに

terraformでGCSバケットを作成しようとした際に以下のようなエラーが出ました。新鮮さを感じたので残しておきたいです。

```jsx
% terraform plan
╷
│ Error: "dev-googlecloud-tfstate" name value cannot contain "google" or close misspellings, such as "g00gle"
│ 
│   with google_storage_bucket.terraform-state-store,
│   on gcs.tf line 2, in resource "google_storage_bucket" "store_of_tfstate":
│    2:   name     = "dev-googlecloud-tfstate"
│ 
╵
```

## TL;DR

`google`文字列はバケット名に使用できないようです。

## 参考

> バケット名に「google」や「google」と類似する表記（「g00gle」など）を含めることはできません。
>
https://cloud.google.com/storage/docs/buckets?hl=ja#naming
部分的な2次元累積和を求めるやり方

# 部分的な2次元累積和を求めるやり方

## 概要
![image](https://gist.github.com/user-attachments/assets/78909dd6-a519-4001-97b8-ec6d905b47ae)
- 青枠内の累積値を以下の手順で求める

1. 左上からの累積値をすべての箇所で算出する
2. 1で算出されたものを利用して部分的な２次元累積和(青枠内)を求める



## 全ての左上からの累積値を求める

### 考え方
- 赤の累積値 + 青の値 = 青の累積値

![image](https://gist.github.com/user-attachments/assets/87be497c-e3c2-4362-8f2b-d82aa4428f09)

### 手順
- 実際のプログラムでは事前準備として累積値の初期値は0なので上に1行、左に1行追加されて6行6列で初期化を行う。

![image](https://gist.github.com/user-attachments/assets/84762b1f-974d-46be-9b69-b26bd8b7d8f4)


1. 上の累積値は27
2. 左の累積値を足すと 27 + 24 = 51
3. 重なる部分の合計を引くと 51 - 15 = 36
4. 元の2次元配列の値 を足すと 36 + 6 = 42

![image](https://gist.github.com/user-attachments/assets/297543e1-b9b9-4df9-9075-86691bb6c988)

- 完成形（実際のプログラムでは左と上の0は不要になるので消しておいたほうがよい。）

![image](https://gist.github.com/user-attachments/assets/887beb21-da95-4787-9f08-1cf8aad8ec95)

## 全体の累積値から部分的な累積値を算出

### 考え方
- 対象範囲を含んだ左上からの累積値 - 不要な部分を取り除いたもの

### 手順
- 先に算出した累積値の２次元配列を使う

1. 左上からの合計値 64
2. 上の合計値を引く 64 - 24 = 40
3. 左の合計を引く 40 - 10 = 30
4. ２重に引いた部分を足す 30 + 3 = 33。よって答えは33

![image](https://gist.github.com/user-attachments/assets/aa8b47e3-a32f-4d0b-afd5-37c8dde6d21c)
CraftLaunchからghqのディレクトリを開く

これまた誰得なネタですが、、、CraftLaunchからghqの登録されたパスをexplorerで開く、みたいなコマンドです。

こんなのを作って
```
    def ge(info):
        subprocess.Popen(['start', 'pwsh', '-nop', '-Command', 'explorer (ghq list --full-path|fzf)'], shell=True)
```

登録します。
```
        ('ge', ge),
```

実行してみました。
![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3740499/ce4e7fdd-621a-2c7a-d4e0-ed95f8d458bc.gif)

フォントが小さいのもあるけれど、つぶれてみえないし、動きもがくがくしてる。もっといいgifに録画できるツールがあるといいのですが、、、とりあえず動きは録れました！

けど、これを使うシーンが来るんでしょうか、、、？？
M5NanoC6とOLED SSD1327で遊ぶ (「46」よろーを表示)(ESP32-C6)



x 過去ログを見よ!!
x Adafruit_GFXとAdafruit_SSD1327をインストール
x M5Nano C6の事
x OLEDは、たぶん、秋月で買った


目的
OLEDで遊ぶ

結果

![o_coq490.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/40e7b015-801a-84b7-7648-055aea0d440e.jpeg)



プログラム


```c++



//ssd1327_46_M6NanoC6_1


//ヘッダーファイル
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1327.h>

//定義
#define SCREEN_WIDTH  128    // OLED display width, in pixels
#define SCREEN_HEIGHT 96    // OLED display height, in pixels
#define OLED_RESET     -1   // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1327 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define setCursorAA(AA,BB) setCursor(AA+16,BB)

//初期化
void setup() {

  // I2Cアドレスは使用するディスプレイに合わせて変更する
  display.begin(SCREEN_ADDRESS);

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  display.clearDisplay();

  // テキストサイズを設定
  display.setTextSize(3);
  // テキスト色を設定
  display.setTextColor(SSD1327_WHITE);
  // テキストの開始位置を設定
  display.setCursorAA(0, 16);

  //46を設定
  int tempval = 46;

  // 1行目に46を表示
  display.println(tempval);

  // 描画バッファの内容を画面に表示
  display.display();

  delay(1000); //1秒待つ

}//loop



```
【gcloud config】新規作成と切り替え方法

## はじめに

gcloud CLIについて、configをdefaultのものだけでなく追加して切り替えられるようにします。

[gcloud compute  |  Compute Engine Documentation  |  Google Cloud](https://cloud.google.com/compute/docs/gcloud-compute?hl=ja)

## 手順

順番に実行していきます。

### 新規configを作成

現状、有効になっているconfigを確認

```jsx
gcloud config list
```

既存のリストを確認

```jsx
gcloud config configurations list
```

新しいconfigを作成する

```jsx
gcloud config configurations create main-config
```

作成されたことを確認

```jsx
gcloud config configurations list
```

作成したconfigを有効にする

```jsx
gcloud config configurations activate main-config
```

gcloud認証を検証する。ブラウザに飛んでgmailアカウントの認証を行う。

```jsx
gcloud auth login
```

### 作成したconfigに設定を追加する

gmailアカウント

```jsx
gcloud config set core/account hogehoge@example.com
```

プロジェクトID

```jsx
gcloud config set core/project fuga-project
```

利用可能なリージョン、ゾーンを確認

```jsx
gcloud compute regions list
gcloud compute zones list
```

デフォルトリージョン、ゾーンを設定

```jsx
gcloud config set compute/region asia-northeast1
gcloud config set compute/zone asia-northeast1-a
```

デフォルトのリージョン、ゾーンを確認

```jsx
gcloud config get-value compute/region
gcloud config get-value compute/zone
```

## まとめ

gcloud cliの設定ファイルについて、追加と切り替え方法を確認しました。

併せて記述すべき設定等があればご指摘いただけますと幸いです。

ありがとうございました。
プロダクトオーナーについて

# はじめに
業務でプロダクトオーナーを任されました。
そのため、役割の重要性を理解し、責任を全うするために、プロダクトオーナーについて深く学ぶ必要があると思いました。

プロダクトオーナーは、スクラム開発における中心的な存在、かつ、顧客やユーザーの声を開発チームに伝え、プロダクトの方向性を決定する重要な役割を担う立場です。

プロダクトオーナーの定義、主要な責任、必要なスキル、そして具体的な役割について学んだことをアプトプットしていきます。

# プロダクトオーナーとは何か
### 定義
> プロダクトオーナーとは、プロダクトの統括を認められた中心的な存在であり、スクラムチームを構成する3つの役割のうち一つである（その他の2つは、スクラムマスターと開発チーム）。

引用：[エッセンシャルスクラム 9章](https://www.shoeisha.co.jp/book/detail/9784798130507)

### 位置付け
ステークホルダー（顧客やユーザー）とスクラムチームの架け橋。
かつプロダクトの方針の最終決定権を持つ者である。

# プロダクトオーナーの主要な責任は何か？
### 責任
エッセンシャルスクラムでは、以下についての述べられている。
> - 経済性の管理
> - プランニングへの参加
> - プロダクトバックログのグルーミング
> - 受け入れ条件の定義と検証
> - 開発チームとの協力
> - ステークホルダーとの協力

引用：[エッセンシャルスクラム 9章](https://www.shoeisha.co.jp/book/detail/9784798130507)

プロダクトオーナーは、経済性の管理からプロジェクト全体の計画立案、開発チームとの密接な協力まで、多岐にわたる重要な責任を担っている。
プロダクトバックログの管理、受け入れ条件の設定と検証、そしてステークホルダーとの協力を通じて、プロダクトの価値を最大化する役割を果たす。
スクラム開発では、プロダクトオーナーがプロジェクト全体に対して、継続的に関与する。
従来の手法と異なり、初期と最終段階だけでなく、常に開発チームと協力し、プロダクトの方向性を決めていく。
結果、迅速な意思決定と価値の高いプロダクト開発を可能にする。

# 必要なスキル
業務知識をもち、ステークホルダーの応じた適切な表現ができるコミュニケーション能力、そして信頼される必要がある。信頼されていなければ、プロダクトは成功しない。（どこかで齟齬が起きる、チーム間の情報伝達がうまくいかない）
また、範囲、日程、コストなどを考慮し、かつステークホルダーからの要求と技術的な難易度調整を行い、決断をしていく力も必要となる。

# 役割
スプリントプランニングへの参加、デイリースクラムへの出席、質問への回答、開発された機能のテストなどがある。
また、ステークホルダーとの対話を通じて、プロダクトバックログの優先順位を常に最適化する必要がある。

# 誰が担うのか
| 開発の種類 | プロダクトオーナーの候補 |
|------------|--------------------------|
| 社内開発 | 開発の恩恵を受ける部門からの代表者 |
| 商用開発 | 顧客の声を代弁できる社員（プロダクトマネージャーなど） |
| 外部委託開発 | 委託元の会社の代表者 |
| コンポーネント開発 | 技術志向の人材 |

大規模なプロジェクトでは、プロダクトオーナーの役割を支援するチームを構成することがある。
ただし、最終的な意思決定は1人のプロダクトオーナーが行うべきことに注意したい。
非常に大規模な開発では、チーフプロダクトオーナー、プロダクトラインオーナー、フィーチャープロダクトオーナーといった階層構造を採用することもあるらしい。
プロダクトオーナーの役割はとても多い。それを遂行するには、適切な人材の選定、明確な責任の定義、そして組織全体のサポートが不可欠である。
【Java】String型の空文字判定とNULL判定

## 1. 空文字とNULLの両方をチェック
- StringUtilsクラスのisEmptyメソッドを使用する
：null または空文字（長さが0）の場合に true を返す

```java:
import org.apache.commons.lang3.StringUtils;

public class StringCheck {
    public static void main(String[] args) {
        String str = null; // ここに対象の文字列をセット

        if (StringUtils.isEmpty(str)) {
            System.out.println("String is null or empty");
        } else {
            System.out.println("String is not null and not empty");
        }
    }
}
```
### 実行結果：
```
String is null or empty
```

## 2. 空文字のみ判定
- String クラスの``isEmpty()``メソッド
- Stringクラスの``equals()``メソッド

：文字列が空文字（長さが0）であるなら true を返します。

```java:空文字判定
import org.apache.commons.lang3.StringUtils;

public class StringCheck {
    public static void main(String[] args) {
        String str = ""; // ここに対象の文字列をセット

        if (str.isEmpty()) {
            System.out.println("String is empty");
        } else {
            System.out.println("String is not empty");
        }
        if (str.equals("")) {
            System.out.println("String is empty");
        } else {
            System.out.println("String is not empty");
        }
    }
}
```
### 実行結果
```
String is empty
String is empty
```
### ※注意点
null が格納された String 型の変数に対して ``isEmpty()``、``equals()``を呼び出すと、NullPointerException が発生する。
そのため、　NULLでないことが確実でない限りは、空チェックの前にNULLチェックも入れること。

```java:NULLチェックを手前で行う
public class StringCheck {
    public static void main(String[] args) {
        String str = ""; // ここに対象の文字列をセット

        if (str != null && str.isEmpty()) {
            System.out.println("String is empty");
        } else if (str == null) {
            System.out.println("String is null");
        } else {
            System.out.println("String is not empty");
        }
    }
}
```
### 実行結果：
```
String is empty
```
Dify入門：生成AIがあなたの資産を倍増させる！

オープンソースのDifyのテンプレートに「Investment Analysis Report Copilot」があり、Yahoo Financeの情報をもとに投資アドバイスを提供してくれます。投資初心者である私にとって非常に役立つツールなので、その内容をまとめました。 
※Difyとは　
https://qiita.com/k__murayama/items/7d94d91194387dc80844


## スキルと目標　
Yahoo Financeを活用し、企業の財務状況と市場ポジションを分析します。具体的には、ティッカーを用いて株式情報、ニュース、財務数値と分析を取得します。

目標は、企業の財務状況の詳細な分析と、市場におけるポジションと競争力の評価です。財務分析では、財務レポートの垂直分析と比率分析を実施し、包括的な分析と結論を導き出します。

市場分析では、業界分類を特定し、市場ポジショニングとセグメンテーション分析を行います。これにより、企業の競争優位性や潜在的なリスクを把握し、投資戦略や事業戦略に役立てることができます。 

## 環境構築
### Dify のインストール
以下、Windows10/11 へDifyをインストールする方法
https://qiita.com/k__murayama/items/7d94d91194387dc80844

### アプリの作成
Dify管理画面にログインしダッシュボートを表示します。

- 「テンプレートから作成」をクリック
![100.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78224/88522125-d1bf-64c6-9498-1b6bd60ecd05.png)

- 「Investment Analysis Report Copilot」を選択し、このテンプレートを使用するを押す
![101.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78224/c4c0211b-9443-5d6d-7b4e-1d26651345d9.png)


- アイコンとアプリ名を決定する
![102.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78224/a7aba84d-ed86-9b32-084a-f7c12c2274ea.png)

- 日本語化
手順にキャラクターが定義されているので、日本語で出力するよう以下のシステムプロンプトに記載
Aanswer all questions in Japanese.　

   ```
   My primary goal is to provide user with expert data analysis advice. Using extensive
   and detailed data. Tell me the stock (with ticket symbol) you want to analyze. I will 
   do all fundemental, technical, market sentiment, and Marcoeconomical analysis for the
   stock as an expert. Aanswer all questions in Japanese.
   ```

- アプリの公開
右上の[公開]　→ 更新　→　アプリの実行

## 試してみる
- プロンプト：楽天グループのファンダメンタル分析をしてください。


### 楽天グループのファンダメンタル分析

#### 基本情報
- **会社名**: 楽天グループ株式会社 (Rakuten Group, Inc.)
- **業種**: インターネット小売 (Internet Retail)
- **セクター**: 消費者向けサイクリカル (Consumer Cyclical)
- **従業員数**: 30,830人
- **設立年**: 1997年
- **CEO**: 三木谷 浩史氏
- **本社所在地**: 日本国 東京都世田谷区玉川一丁目14番1号
- **ウェブサイト**: [https://global.rakuten.com/corp](https://global.rakuten.com/corp)

#### 財務データ取得日とソースリンク
- 取得日: 2023年4月時点の最新情報を使用しています。
- ソース: Yahoo Finance ([4755.T](https://finance.yahoo.com/quote/4755.T))

#### 貸借対照表、損益計算書、キャッシュフローの分析結果
**バランスシート**
- 総資産: 6,147億円
- 総負債: 5,437億円

**損益計算書**
- 純利益: -2754億円（赤字）
  
**キャッシュフロー**
- オペレーティングキャッシュフロー: 1,150億円

#### 各種比率分析結果
**収益性比率**
- 売上高純利益率(Net Profit Margin): -12.81%

**安全性比率**
- 自己資本比率(Equity Ratio): 純資産 / 総資産 = (6147 - 5437) / 6147 = 約11.56%
  
**効率性比率**
- ROA(Return on Assets): -0.27%
  
**市場価値比率**
- PBR(Price to Book Ratio): 株価 / BPS = 913 / 400.199 ≈ 2.28倍

#### 全体的な結論、リスク、機会についての記録
楽天グループはインターネット小売業界において多角的なビジネスを展開しています。しかし、財務データからは高い負債と赤字が見られるため、現在は厳しい財務状況にあることが伺えます。自己資本比率が低く、ROAもマイナスであるため、収益性と効率性に課題があります。ただし、オペレーティングキャッシュフローはプラスであり、事業活動を通じて現金を生み出している点は評価できます。

市場価値に関してはPBRが2.28倍となっており、市場からの評価はそれなりにあることを示唆しています。ただし、将来的な成長や収益改善への期待が反映されている可能性も考えられます。

リスク面では高い負債水準と持続する赤字が挙げられます。一方で機会としては電子商取引市場の拡大や新規事業への進出による成長ポテンシャルがあります。

以上の分析結果を踏まえた上で投資判断を行う必要があります。

## おわりに
投資は自己責任でお願いします。

以上です。
[CopilotStudioで作る業務効率化のAIチャットボット]書籍まとめ1

# 背景
近年、ChatGPTをはじめ、AIが台頭してきました。とある勉強会で[CopilotStudioで作る業務効率化のAIチャットボット](https://book.impress.co.jp/books/1124101025)という書籍に出会って、**これからの時代必要になりそうな実践的な書籍**だったので、学習したこをとまとめてみました。

# 読んだ書籍
[CopilotStudioで作る業務効率化のAIチャットボット](https://book.impress.co.jp/books/1124101025)

**益森貴士** 著
2024/10/2に出版された本です。

![CopilotStudioで作る業務効率化のAIチャットボット_書籍_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/0a21c6f3-29c7-e7dc-a041-e66f647594d9.png)


**業務効率化を目指すビジネスパーソン**に向けた実践的なガイドブックでした。本書は、**Microsoftの「Copilot Studio」を活用して、独自のAIチャットボットを作成**する方法を詳しく解説しています。

# 概要
#### 1.Copilot Studioの概要
**「Copilot Studio」は、Microsoftが提供するツールで、ローコードで独自のCopilot（AIアシスタント）を作成**できます。これにより、業務プロセスの自動化や顧客サービスの向上が可能になります。

#### 2.基礎知識と準備
本書の初めの章では、**Copilot Studioの基本的な使い方や設定方法**について説明しています。これには、必要なソフトウェアのインストールや初期設定が含まれます。

#### 3.簡単なCopilotの作成
次に、**簡単な業務効率化のためのCopilotを実際に作成する手順**が紹介されています。具体的な例として、注文状況を答えるチャットボットや、顧客の声を効率的に処理するチャットボットの作成方法が挙げられています。

#### 4.他システムとの連携
本書では、**Power AutomateやAI Builderなどの他のMicrosoftツールと連携して、より高度な機能を持つCopilotを作成する方法**も解説されています。これにより、CRMシステムやERPシステムと連携し、業務全体の効率化を図ることができます。

#### 5.応用編と展開方法
最後に、**作成したCopilotの機能を拡張し、FAQに答える汎用的なCopilotを作成する方法**や、**カスタムCopilotの展開・運用方法**についても詳しく説明されています。

# 所感
[CopilotStudioで作る業務効率化のAIチャットボット](https://book.impress.co.jp/books/1124101025)を読んで感じたことを以下にまとめました。
#### 章の目標が明確でわかりやすい
各章の目標が明確に設定されているため、**自分がどこに向かって学習を進めているのか**を常に認識できます。これにより、学習の進捗を把握しやすく、効率的に学習を進めることができました。
#### 文章の体裁のメリハリがよい
本書は、太字やアンダーライン、図解を効果的に使用しており、**重要なポイントが一目でわかる**ようになっています。特に、図解に解説が挿入されていることで、実践的な理解が深まりました。
#### 章の流れが適切である
**各章の流れが非常にスムーズで、開発を始める際に知りたい情報が違和感なく順序立てて書かれています**。これにより、学習が途切れることなく進められ、非常に学びやすい構成となっています。

このように、[CopilotStudioで作る業務効率化のAIチャットボット](https://book.impress.co.jp/books/1124101025)は、読者が効率的に学習できるように工夫された一冊です。業務効率化を目指す方にとって、非常に有用なガイドブックであると感じました。

# まとめ
[CopilotStudioで作る業務効率化のAIチャットボット](https://book.impress.co.jp/books/1124101025)に出会って、CopilotStudioを使用して、オリジナルのチャットボットを作るにはどうしたらよいか分かりました。
まずは、全体的に一読して、概要を把握しました。
今後は、**5.応用編と展開方法**あたりをハンズオンしてみて、理解を深めていこうと思います。また、学習した例をもとにして、**要件に合わせて、カスタマイズしてみよう**と考えております。

ぜひ、気になる方は[CopilotStudioで作る業務効率化のAIチャットボット](https://book.impress.co.jp/books/1124101025)を購入してみてください。

この記事が皆さんの役に立てば幸いです。何か質問があれば、コメント欄で教えていただけると幸いです！
ExcelVBAで選択範囲のURLに一括でハイパーリンクを設定する

ExcelのセルにURLがある場合に、ハイパーリンクを設定したいときは、URLを入力したセルをF2で編集モードにしてEnterすれば自動的にハイパーリンクになります。
しかし、下記画像例のようにハイパーリンクを設定したいURLを含むセルが複数ある場合は、セルの１つ１つをF2で編集モードにしてEnterするのは大変ですよね。

![スクリーンショット 2024-10-06 172531.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3479442/40afdf5d-ad69-9eb7-01e0-740efb60f627.png)

そんなときは、URL化したいセル範囲を選択しながら、下記のコードを実行します。

![スクリーンショット 2024-10-06 171554.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3479442/2917691c-7d12-4522-fcc4-89e6e6f73576.png)

コードはこちらです。

```vb:ExcelVBA
Sub sb選択範囲のURLをリンクにする()
' アクティブシートの選択範囲内のセルに含まれるURLをハイパーリンクに変換する処理
    
    Dim rngSelected As Range ' 選択範囲を格納する変数
    Dim cell As Range ' 各セルを処理するための変数
    Dim strURL As String ' セル内のURLを格納する変数
    Dim ws As Worksheet ' アクティブシートを格納する変数
    
    ' アクティブシートを取得
    Set ws = ActiveSheet
    
    ' 選択範囲を取得
    Set rngSelected = Selection
    
    ' 選択範囲の各セルをループ処理
    For Each cell In rngSelected
        ' セルの内容がURL形式か確認
        strURL = CStr(cell.Value) ' セルの値を文字列として取得
        If zfIsURLValid(strURL) Then
            ' URLが有効な場合、そのセルにハイパーリンクを設定
            ws.Hyperlinks.Add Anchor:=cell, Address:=strURL, TextToDisplay:=strURL
        End If
    Next cell
    
    Dim myMsg As String 'メッセージボックス用変数
    myMsg = "処理が終了しました。"
    MsgBox myMsg, , "処理結果通知"

End Sub

Function zfIsURLValid(ByVal a_strURL As String) As Boolean
' URLが有効かを確認する関数
' 簡易的なURL形式のチェックを行う
    
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    
    ' URLの正規表現パターンを設定
    With regex
        .Pattern = "^https?://[^\s/$.?#].[^\s]*$"
        .IgnoreCase = True
        .Global = False
    End With
    
    ' URLが正規表現に一致するかを確認
    zfIsURLValid = regex.Test(a_strURL)
End Function
```

実行結果は下記のようになります。

![スクリーンショット 2024-10-06 173320.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3479442/f3cf3b71-959c-2de7-5dc1-d238360b7247.png)

ちなみにハイパーリンクの一括削除は、該当のセルを範囲選択して、右クリックで「ハイパーリンクの削除」ボタンがあるので、それで一括削除可能です。
右クリックで「ハイパーリンクの削除」ボタンがなぜか出てこない場合は、ハイパーリンクの書式（青字、アンダーライン等）のみが残っている可能性があります。

なお、こちらのコードはこのnoteの[有料記事（【無料部分あり】ExcelVBAコードを生成するプロンプトのコツと解説（全19項目）](https://note.com/keiri_info/n/na5da667e42cf)で紹介しているプロンプトでchatGPTで作成しました。

:::note warn
ハイパーリンクを設定したのが、PowerQueryでデータ加工してテーブルに呼び出しているテーブルの列の場合は、データ更新した際にハイパーリンク設定が消えてしまうようです。（アンダーラインやフォントカラー等の書式設定は残ります。）
そのため、PowerQueryでデータ加工してテーブルに呼び出しているURLに、都度ハイパーリンクを設定したい場合には、そのブックをマクロ有効ブックに変更して問題ないのであれば、クラスモジュールでクエリ更新時のイベントプロシージャを利用してURLへのハイパーリンクを設定をするようにできます。
[参考：クエリ更新時のイベントプロシージャ](https://note.com/s_takushi/n/n949fddc85ba8)

ただし、そのようにする場合は、選択範囲のURLに対してハイパーリンクを設定するのではなく、テーブルの特定列に設定するというコードに書き換えます。
:::

:::note info
VBAを使用せずに、ワークシート関数のHYPERLINK関数を使用して一括でハイパーリンクを設定する方法もあります。
ただし、HYPERLINK関数の場合には、既存のURLが入力された列とは別の列を挿入してHYPERLINK関数を挿入する形になります。（表示文字列は変更可能）

![スクリーンショット (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3479442/ccdb14f9-e92c-96a2-dd4a-7fe5cbcf5c48.png)

前述の、ハイパーリンクを設定したのが、PowerQueryでデータ加工してテーブルに呼び出しているテーブルの列の場合は、こちらの方法の方が良いかもしれません。
ただし、HYPERLINK関数で表示文字列を指定しないと全く同じURLを表示する列が2列になってしまうので、表示文字列は短く端的に指定するとよいでしょう。
:::