OmniAICreator/Qiita-1.07M huggingface dataset:
AWS Cloudwatch Logsの内容をWindows11にCSVでダウンロードする

## 環境
Windows11(23H2)
aws-cli/2.15.58 Python/3.11.8 Windows/10 exe/AMD64

## 準備
- jqのインストール

以下を参考にインストール実施
https://blog.serverworks.co.jp/2021/12/20/180000_2

- jq動作確認
参考サイトでバージョン確認しているが物足りないと思った（というかバージョン確認できたのにそのあといろいろエラー出て全然動いてくれなかった）ので以下を実施

CloudWatchLogsのロググループ一覧取得
また自身の環境に合わせて以下は置換してください
${profilename}：プロファイル名
```
aws logs describe-log-groups --profile ${profilename} --query "logGroups[].{logGroupName:logGroupName,storedBytes:storedBytes,creationTime:creationTime}"| jq -r ".[]|[.logGroupName,.storedBytes,.creationTime] | @csv"
```
出力例
```
"/aws/lambda/test_lambda",11096,1626334018940
"/aws/lambda/dynamodb_catalog",20915,1670830215315
"/aws/rds/instance/database-acs/postgresql",4184,1654505982681
"/vpclog",0,1717463269522
```

## AWS Cloudwatch Logsの内容をCSVで表示、ダウンロード
- 表示してみる
動作確認同様以下は置換してください

${profilename}：プロファイル名

${loggroupname}：ロググループ名

${logstreamname}：ログストリーム名
```
aws logs get-log-events --profile ${profilename} --log-group-name ${loggroupname} --log-stream-name ${logstreamname} --start-from-head --query "events[].{timestamp:timestamp,message:message}"| jq -r ".[]|[.timestamp,.message] | @csv"
```
出力例
```
1654507128000,"2022-06-06 09:18:48 UTC::@:[10545]:LOG:  redo starts at 0/C000178"
1654507128000,"2022-06-06 09:18:48 UTC::@:[10545]:LOG:  invalid record length at 0/1001BA38: wanted 24, got 0"
1654507128000,"2022-06-06 09:18:48 UTC::@:[10545]:LOG:  redo done at 0/1001BA00"
1654507128000,"2022-06-06 09:18:48 UTC::@:[10545]:LOG:  checkpoint starting: end-of-recovery immediate"
```

- ダウンロード（というか出力先指定して出力するだけ）
```
aws logs get-log-events --profile ${profilename} --log-group-name ${loggroupname} --log-stream-name ${logstreamname} --start-from-head --query "events[].{timestamp:timestamp,message:message}"| jq -r ".[]|[.timestamp,.message] | @csv" > 出力先パス
```
戻り値なし

指定した出力先確認してファイルが出力されていればOK


## 最後に
タイムスタンプが日本時間に直せてないからそこはエクセルとかでどうにかするか、ほかの方法検討したい。
いい方法知ってたら教えてください！
【ChatGPT＋DALL-E3】クァールを描きます。頭の中のイメージをChatGPTに伝える方法も。


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

　今回は、ちょっとした理由があり、クァールを描きます。クァールとはなんぞや？　SF小説なんかを読む方はご存知かも。最後には、頭の中のイメージをChatGPTに伝える方法も書きます。

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

　今回は、
　　声優・巻島直樹さんの
　　　訃報が入ったので、
　　　　その死を悼んでのものです。
　　　　　享年61歳だそうです。

　声優・巻島直樹さんの
　　御冥福をお祈りします。
***
　さて、
　　巻島直樹さんが
　　　担当された役は
　　　　たくさんあります。
　　　　　詳しくは、Wikipedia参照を。

　その中に
　　アニメ
　　　『ダーティペア』シリーズが
　　　　あります。

　『ダーティペア』シリーズは
　　高千穂遙先生原作のSF小説です。

　簡単に内容を説明すると
　　トラブル解決を
　　　生業とする組織があり、
　　　　そこから派遣される
　　　　　スタッフが活躍します。

　そのスタッフである二人組、
　　コードネーム
　　　『ラブリーエンジェル』が
　　　　巻き起こすドタバタなのです。
　　　　　人呼んで『ダーティペア』。

　その二人組とともに
　　宇宙船に乗り込む仲間として
　　　黒豹のような姿の生物、
　　　　クァールがいます。
　　　　　名前は、ムギ。

　このクァール、
　　A・E・ヴァン・ヴォークトの
　　　古典SF小説
　　　『宇宙船ビーグル号の冒険』に
　　　　登場する同名の生物。

　詳しくは、
　　Wikipediaに譲ります。

　巻島直樹さんは
　　このクァール、
　　　ムギの声を担当されました。
　　　　人語を話すわけではなく、
　　　　　鳴き声になりますけどね😅
***
　説明はさておき、
　　本題に入りましょう。

　先にも書きましたが、
　　クァールは、黒豹に似ています。
　　　ただ触手があったりするので、
　　　　黒豹そのままというわけには
　　　　　いきません。

　やり取りをどうぞ。
***
***user***
クァールを描いて。正方形で描画。

なお、クァール（英語: Coeurl）とは、A・E・ヴァン・ヴォークトの古典SF小説『宇宙船ビーグル号の冒険』を参照して

***ChatGPT***
（黒豹の頭を持つタコ的なものが……）

***user***
リトライ

***ChatGPT***
（脚長黒豹。尻尾がクネクネ）

***user***
前脚の付け根に触手をお願いします

***ChatGPT***
（だいぶ似てきた。このままいこう）

***user***
クァールが宇宙船の白い壁を破壊してまわっている

***ChatGPT***
![Coeurl_from_Space_Beagle.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/a84e8a18-6283-e0d8-8782-64d1f77a4064.jpeg)
***

　白い壁の予定が
　　宇宙船の
　　　コントロールルームみたいに
　　　　なっちゃった😅

　黒豹が白くなってるし😅

　でも
　　いい感じなので
　　　これでX-Twitterにアップ。
***
　最後に、
　　頭の中のイメージを
　　　ChatGPTに伝える方法です。

　目的物に
　　近付けるのは
　　　大変です。

　すでに誰かが
　　その目的物を
　　　説明している場合、
　　　　今回のように、それを
　　　　　参照するように言ったり、
　　　　　　コピペします。

　もしも
　　オリジナルならば、
　　　それを言語化しなければ
　　　　なりません。

　言語化を、普段から
　　やっている人は
　　　苦労もしません。

　しかし、
　　画像生成している方の
　　　多くは、違うかと思います。

　そこで
　　言語化を
　　　ChatGPTに任せる、
　　　　という手もあります。

　少し絵心があれば、
　　落書き程度でも、絵を描いて、
　　　ChatGPTに解析させれば、
　　　　言語化してくれます。

　ここに
　　補足情報を
　　　追加すれば、
　　　　もっとイメージに
　　　　　近付けられます。

　ちなみに
　　この補足情報は
　　　落書き絵の解析時に
　　　　一緒に書き込む方が
　　　　　良さげです。

　言語化された内容を
　　よく見て、そのままか
　　　修正・削除して
　　　　画像生成を
　　　　　行ないます。

　これは
　　言語化の勉強にも
　　　なりますので
　　　　いろんな画像を
　　　　　やってみてください😊

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

　今回は、ここまで。
robloxでassistant その103

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
梯子を作れ。

# 手順
- ReplicatedFirstに、LocalScriptを追加。
- スクリプトを書く。
```

local part = Instance.new("TrussPart", workspace)
part.Size = Vector3.new(1, 20, 1)
part.Position = Vector3.new(-1, 10, -10)
part.Anchored = true



```
  
# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/97d32011-6f8f-f07f-ad70-318d1f933da8.png)


以上。
GitLab Update(13.8.8⇒16.11.2)

# このドキュメントの目的

* GitLabをv13.8.8からv16.11.2までの更新手順を記録し、今後のバージョンアップに役立てる

# 動作環境

* Hyper-V上のUbuntu

# 更新手順

更新は次の手順で進める
1. アップデートパスを確認
1. 現環境のバックアップ
1. debパッケージをダウンロード＆インストール

## 事前準備

1. GitLabのバージョンを確認する
    ```
    sudo gitlab-rake gitlab:env:info
    ```
1. GitLabのサイトでアップデートパスを確認する
https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/

## バックアップ

1. Hyper-Vのバックアップを作成する（バックアップはこれだけで良いかも）
1. データベースをバックアップする
    ```
    sudo gitlab-backup create
    ```
1. 設定をバックアップする
    ```
    sudo cp -ap /etc/gitlab <任意のディレクトリ>
    ```
1. アップデート時の自動バックアップを禁止する
/etc/gitlab/に skip-auto-backup を作成

## 更新実行(例：14.0.12)

1. アップデートパスで確認したバージョンのGitlLabをwgetでダウンロードする
アーカイブ：https://packages.gitlab.com/gitlab/gitlab-ce
    ```
    wget --content-disposition https://packages.gitlab.com/gitlab/gitlab-ce/packages/ubuntu/focal/gitlab-ce_14.0.12-ce.0_amd64.deb/download.deb
    ``` 
    認証に失敗する場合、末尾に --no-check-certificate を付ける
1. GitLabをアップデートする
    ```
    sudo dpkg -i gitlab-ce_14.0.12-ce.0_amd64.deb
    ```
    更新後、gitlabにアクセスしてバージョンが更新されていることを確認
1. マイグレーション終了を確認
  次のコマンドを実行して、「0」が出力されれば終了。数時間かかることもあるので気長に待つこと。
    ```
    sudo gitlab-rails runner -e production 'puts Gitlab::BackgroundMigration.remaining'
    ```
1. GitLabにアクセスして動作確認する

# 備考

* aptを使っていないので、debコマンドでインストールする

* 14世代より、HTTPサーバーがpumaだけになったので、unicornを禁止しpumaだけを使うようにした
1. /etc/gitlab/gitlab.rb を編集
    ```
    unicorn['enable'] = false
    puma['enable'] = true
    ```
1. 次のコマンドで再設定
    ```
    sudo gitlab-ctl reconfigure
    ```
1. 次のコマンドでunicornが動いていないことを確認
    ```
    ps axwwu | grep unicorn
    ```

* 容量が足りないとき  
データベースのバックアップをどんどん作っていくと、容量不足でアップデートに失敗したり、GitLab自体が動作しなくなることもある。そのときは下記フォルダにあるデータベースのバックアップを削除すること。
/var/opt/gitlab/backups

* 不要なテーブルを削除
Ver.14.5よりdiffのテーブル構成が変わったらしい。次のコマンドを実行することでデータベース容量を圧縮することができる模様。  
https://gitlab-docs.creationline.com/ee/update/versions/gitlab_14_changes.html#1450  
https://qiita.com/wadakatu/items/b7b5ef486a67d6ec2455  
  ```
  gitlab-psql
  VACUUM FULL merge_request_diff_commits
  ```

# 参考

[アップグレード手順（Ver.13 ~ Ver.14.6.2まで)]
(https://qiita.com/wadakatu/items/9c9b08874fb1372df382)
Actix-webでWASM

Actix-webでWASMを利用してみます。

テキストボックスに数値を入力し、ボタンを押すと＋１した結果をラベルに記載する、というプログラムを作成してみます。

最初にWASMプロジェクトを作成します。
プロジェクト名を「wasm1」とします。

```
cargo generate --git https://github.com/rustwasm/wasm-pack-template
Project Name: wasm1

cd wasm1
```

Cargo.tomlファイルは下記のとおりに作成されます。

wasm1/Cargo.toml

```
[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = ["console_error_panic_hook"]

[dependencies]
wasm-bindgen = "0.2.84"

console_error_panic_hook = { version = "0.1.7", optional = true }

[dev-dependencies]
wasm-bindgen-test = "0.3.34"

[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
```

lib.rsファイルの内容をプラス１する内容に書き換えます。

wasm1/src/lib.rs

```
mod utils;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn plus1(x: i32) -> i32 {
    x+1
}
```

WASMプロジェクトをビルドします。

```
wasm-pack build
```

別フォルダにWebプロジェクト（webapp1）を作成します。

```
cd ..
cargo new webapp1
cd webapp1
```

Cargo.tomlファイルのdependenciesに依存関係を追加します。

webapp1/Cargo.toml

```
[dependencies]
actix-web = "4.0"
actix-files = "0.6"
```

main.rsファイルにWebサーバーを設定する為、書き換えます。

```
use actix_files::Files;
use actix_web::{App, HttpServer, web, HttpResponse};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(Files::new("/", "./static").index_file("index.html"))
    })
    .bind("0.0.0.0:8080")?
    .run()
    .await
}
```

ホームページ（index.html）ファイルを作成します。

```
mkdir static
cd static
touch index.html
```

webapp1/static/index.html

```
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Actix Web with WASM</title>
</head>
<body>
  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

  <input type='text' name='textbox1' value='0'><label> + 1</label><button id='button1' >=</button><label id='label1'>1</label>

  <script type='text/javascript'>

    $(window).on('load', function()
    {
      $('#button1').click(function()
        {
          const wasm = '/wasm1_bg.wasm'

          fetch(wasm)
            .then(response => response.arrayBuffer())
            .then(bytes => WebAssembly.instantiate(bytes, {}))
            .then(results =>
            {

              var num1 = Number($('input[name="textbox1"]').val());

              $('#label1').text(results.instance.exports.plus1(num1));

            })
        });
    });

  </script>

</body>
</html>
```

wasm1プロジェクトでコンパイル後に作成された「wasm1_bg.wasm」ファイルを
webapp1プロジェクトのstaticフォルダ下にコピーします。

```
cd ../../wasm1/pkg
cp -r ./wasm1_bg.wasm ../../webapp1/static/
```

webapp1プロジェクトに戻ってコンパイル＆実行します

```
cd ../../webapp1
cargo build
cargo run
```

```localhost:8080/```にアクセスして、テキスボックスに数値を入力し、ボタンを押すと、+1した結果をラベルに表示します。

![20240604_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87133/fef14588-d1e9-a420-13ba-ac5a77e253c2.png)


環境
ホストPC：Windows10
VirtualBox：ArchLinux
cargo：cargo 1.78.0 (54d8815d0 2024-03-26)
rustup：rustup 1.27.1 (54dd3d00f 2024-04-24)
wasm-pack：wasm-pack 0.12.1

以上
毎日ABC day12【c++】ABC334 A-C問題解説【ACコード付き】

# AtCoder Beginner Contest 334

https://atcoder.jp/contests/abc334

## A - Christmas Present
グローブとバットの値段が与えられるので、単純に比較して高い方を出力する。

```cpp
int B, G;

int main()
{
	cin >> B >> G;
	if (B > G)
	{
		cout << "Bat" << endl;
		return 0;
	}
	else
	{
		cout << "Glove" << endl;
		return 0;
	}
}
```

## B - Christmas Trees
木が一定間隔で立っている時、ある指定の期間に何本立っているかという問題。

指定地点に一番近い左側の木を求める関数を作成するのだが、負の数の時に単純に $x/M$ としてはいけないことに注意。

```cpp
long long A, M, L, R;

long long left_tree(long long x)
{
	if (x % M == 0) return x / M;
	else if (x < 0) return (x / M) - 1;
	else return x / M;
}

int main()
{
	cin >> A >> M >> L >> R;
	// 木の一番右を求める
	R -= A;
	L -= A;
	long long count = 0;
	cout << left_tree(R) - left_tree(L - 1) << endl;
	return 0;
}
```

## C - Socks 2
$N$本のうち、$K$ 本のソックスが片足分になってしまった。なるべく色（数字で与えられる）の絶対値の総和が大きくならないように全てのペアを作りたい。その時の総和はいくらになるか、という問題。

Kが偶数の時には特に困らない。ソートして小さい方からペアにしていくだけだ。

しかし、Kが奇数の時、、どの1枚をペアにしないかを選択しなければならない。

当初は、奇数の場合に除くソックス1つを全てのパターンで計算し直していたので、TLEになってしまった。（WAも2ケースくらいあった）

そこで解説を覗くと、前からの累積和と後からの累積和を求めておくという発想が。この問題でも累積和が使えるとは。。累積和が染み付いてない証拠。どっかで特訓dayを設けたい。

```cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

int N, K;
int A[200009];
long long pre_cum_sum[200009];
long long suf_cum_sum[200009];

int main()
{
    cin >> N >> K;
    for (int i = 1; i <= K; i++) cin >> A[i];
    vector<int> socks;
    for (int i = 1; i <= K; i++) socks.push_back(A[i]);
    sort(socks.begin(), socks.end());
    for (int i = 0; i < K; i++) A[i] = socks[i];

    // 前から累積和
    pre_cum_sum[0] = 0;
    for (int i = 1; i <= K; i++) {
        pre_cum_sum[i] = pre_cum_sum[i - 1];
        if (i % 2 == 0) pre_cum_sum[i] += A[i - 1] - A[i - 2];
    }

	// 後ろから累積和
    suf_cum_sum[K] = 0;
    for (int i = K - 1; i >= 0; i--) {
        suf_cum_sum[i] = suf_cum_sum[i + 1];
        if ((K - i) % 2 == 0) suf_cum_sum[i] += A[i + 1] - A[i];
    }

    long long ans = 1e9;
    for (int i = 0; i <= K; i += 2) {
        ans = min(ans, pre_cum_sum[i] + suf_cum_sum[i]);
    }
    cout << ans << endl;
    return 0;
}

```

```cpp
// WA, TLEのコードです
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

int N, K;
int A[200009];

int main()
{
    cin >> N >> K;
    for (int i = 1; i <= K; i++) cin >> A[i];
    vector<int> socks;
    for (int i = 1; i <= K; i++) socks.push_back(A[i]);
    sort(socks.begin(), socks.end());
	for (int i = 0; i < K; i++) A[i] = socks[i];
    long long ans = 0;

    if ((2 * N - K) % 2 == 0)
    {
        for (int j = 0; j < K / 2; j++)
        {
            ans += abs(A[j * 2] - A[j * 2 + 1]);
        }
    }
    else
    {
        ans = 100000000000000000;
        for (int i = 0; i < K; i++)
        {
            long long ans_tmp = 0;
			int j = 0;
			while (j < (K - 1) / 2)
            {
				if (j + 1 == i)
				{
					ans_tmp += abs(A[j] - A[j + 2]);
					j++;
				}
				else if (j == i)
				{
					ans_tmp += abs(A[j + 1] - A[j + 2]);
					j++;
				}
                else ans_tmp += abs(A[j] - A[j + 1]);
				j += 2;
            }
            ans = min(ans_tmp, ans);
        }
    }
    cout << ans << endl;
    return 0;
}

```
Chatter External  ユーザの検討


まずはできること、できないことの確認

+ [Chatter FreeユーザとChatter Externalユーザについて](https://sf.forum.circlace.com/articles/825813460402049024)
+ [Chatter ユーザーライセンス](https://help.salesforce.com/s/articleView?id=sf.users_license_types_chatter.htm&type=5)

このライセンスは、会社のメールドメイン外のユーザー向けです。外部ユーザー (顧客ともいう) は、顧客を許可する Chatter グループに招待されます。顧客は、招待されたグループでのみ情報にアクセスでき、そのグループのユーザーとのみ会話できます。Chatter オブジェクトやデータにはアクセスできません。Chatter External ユーザーはユーザープロファイルを表示できますが、編集することはできません。


|できること	|通常のユーザ(ライセンス問わず）	|Chatter Free	|Chatter External|
|:----------|:------------------------------|:------------------|:---------------------|
|システム管理者での 代理ログイン	|〇	|×	|×|
|自身がメンバーとなっている Chatterグループへの投稿	|〇	|〇	|〇|
|Chatterタブ内での「会社の注目」の投稿内容	|〇	|×	|×|
|自身のユーザ画面からの投稿（図1）	|〇	|〇	|×|
|「人」タブに表示されるユーザ	|全てのユーザ	|全てのユーザ	|メンバーとなっているChatterグループのユーザ|
|メンションできるユーザ	|全てのユーザ	|全てのユーザ	|全てのユーザ|
|レコードの閲覧	|〇	|×（※一部例外あり）	|×|
|レコードからのメンション	|〇	|〇	|〇|
|Chatterグループ内での マネージャ（Admin）の付与	|〇	|〇	|〇|
|該当ユーザをフォローする	|〇	|〇	|×|

Chatter Freeユーザには、「会社の注目」が見ており、このタブから「社内のやり取り」が見えてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/5b56e63f-4a7a-1da6-66a8-2e835fb39d19.png)

Chatter Extarnalユーザは、「会社の注目」がない分、「社内のやりとり」見えません。
ただ懸念点として、「人」「グループ」タブのリストビューから、閲覧させたくない社内のユーザの情報等も見える可能性があるので、アプリケーションランチャーでも表示されないようタブの非表示の制御等も行うことを推奨いたします。
（この環境はSalesforce Chatterのアプリはデフォルトのままです。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3eac8543-0717-6549-1797-da92026e5812.png)




# 関連資料

+ [Chatterプロファイルからレコードタイプを削除](https://qiita.com/Keiji_otsubo/items/178a5c6933618ffb2b30)
+ [Experience Cloud コミュニティユーザーは Experience Cloud 上で Chatter グループを共有できますが、Salesforce 内部の Chatter グループは共有できないと思います。](https://qiita.com/Keiji_otsubo/items/f7396a7effc0f34c8239)
+ [Chatter から Salesforce へユーザライセンスを変更する方法](https://help.salesforce.com/s/articleView?id=000384799&type=1)

:::note
システム管理者は、Chatter Free、Chatter External、または Chatter Only ライセンスで割り当てられたユーザを、ユーザの詳細ページからいつでも標準の Salesforce ライセンスに変更することができます。
:::

+ [Experience Cloud の考慮事項](https://qiita.com/Keiji_otsubo/items/7afc697db7b1b36176d7)

:::note
Customer Community、Customer Community Plus、および External Identity ライセンスを使用している場合は、Experience Cloud サイトが属する Salesforce 組織内でユーザ名が一意である必要があります。
:::

+ [ライセンス間のコミュニティユーザーの移行](https://help.salesforce.com/s/articleView?id=sf.networks_migrate_users_between_licenses.htm&type=5)

   + Customer Community または Partner Community と Customer Community Login または Partner Community Login ライセンス間
   + Customer Portal または Partner Portal と Customer Community または Partner Community ライセンス間

> この変更にはシステム管理者の作業が伴い、新しいユーザーレコードの作成が必要です。

  + Customer Community と Customer Community Plus ライセンス間

> Customer Community Plus ユーザーが使用可能な高度な共有オプションを Customer Community ユーザーも使用できるようにしていることを確認してください。

# 具体的な設定例

+ [外部ユーザー Chatter 投稿停止通知](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000OTb4)

:::note
チャッター投稿の詳細をキャプチャし、特定の種類のユーザーや投稿の通知を抑制するフローを考えています。

または、内部ユーザーのみがアクセスできるプライベートChatterグループを作成し、フローを使用してそこに更新を投稿すると、外部ユーザーにはこれらの投稿に対する内部コメントが通知されません。
:::
cscの作法 その505

# 概要
cscの作法、調べてみた。
wpf見つけたので、msbuildでコンパイルしてみた。

# 参考にしたページ

https://qiita.com/noriseto/items/3b7fc9af433152539d4a

# 環境
windows11

# ビルドを書く。

```

<Project DefaultTargets='Build' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
	<PropertyGroup>
		<Configuration>Debug</Configuration>
		<Platform>AnyCPU</Platform>
		<RootNamespace>Test</RootNamespace>
		<AssemblyName>WpfApp3</AssemblyName>
		<OutputPath>.\bin\Debug\</OutputPath>
	</PropertyGroup>
	<ItemGroup>
		<Reference Include='System' />
		<Reference Include='System.Xml' />
		<Reference Include='WindowsBase' />
		<Reference Include='PresentationCore' />
		<Reference Include='PresentationFramework' />
		<Reference Include="System.Xaml">
			<RequiredTargetFramework>4.0</RequiredTargetFramework>
		</Reference>
	</ItemGroup>
	<ItemGroup>
		<ApplicationDefinition Include="app3.xaml" />
		<Page Include="MainWindow.xaml" />
		<Compile Include='User.cs' />
		<Compile Include='MainWindowVM.cs' />
		<Compile Include='MainWindow.xaml.cs' />
	</ItemGroup>
	<Import Project='$(MSBuildBinPath)\Microsoft.CSharp.targets' />
	<Import Project='$(MSBuildBinPath)\Microsoft.WinFX.targets' />
</Project>


```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/0639321b-0661-3ce7-c3da-f473aff9b623.png)


以上。
レスト構文 [JavaScript]

レスト構文は、「...」と点を３つ書いて表現するものとなりますが、
以前書かせて頂いたスプレッド構文と似ているものになるのでごちゃごちゃにならないように整理したいと思います。

簡単に区分けするのであれば、

スプレッド構文　＝　「広げるイメージ」
レスト構文　＝　「集めるイメージ」

で覚えればいいかと思います。
特に、英語のスプレッドは「拡散」という意味もあり、ゲームやアニメを多少かじっている人であれば耳馴染みもあるかと思います。

それでは、スプレッド構文は、前回まとめた記事を参照していただき、今回はレスト構文についてまとめていこうと思います。

https://qiita.com/shisshi_engineer/items/9c75dae5ba1834bc5ed3

## 目次：
- [レスト構文](#レスト構文)
- [まとめ](#まとめ)

## レスト構文

>参照：MDN
>残余引数構文により、関数が不定数の引数を配列として受け入れることができ、可変長引数関数を JavaScript で表すことができます。

とあります。

#### 1-1. 例：パラメータの中身の合計値を出力する。

...「ドットを３つ」書いたパラメータをパラメータを用意することにより、
その位置にある残りの引数を配列の中に入れることができます。


```js

function sum(...nums) {
    return nums.reduce((total, num) => total += num);
}

sum(1,2,3);
```

1. sumという関数を定義します。
2. 「...nums」とレスト構文を使い、 numsの中には、配列として値が格納されます。
3. 配列numsに対して、reduceメソッドを使用し、numsの中身の合計値を出力します。
3-1. 第一パラメータには、最終の合計値（total）、第二パラメータには、各々の配列の値(num)を書きます。
3-2. アロー関数で、暗黙的returnを使用し、totalにnumを+する式を記載します。
4. sumの中に合計値を求めたい値
例：sum(3,4,5)
と入力すると、合計値(12)を返してくれます。

配列のreduceメソッド参照：

https://qiita.com/shisshi_engineer/items/2abced20c108daaaeb7e#6-reduce%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89
```text:出力結果：
6
```
今回は、sumに1,2,3を渡しているので、合計値は６となります。

#### 1-2 例： 使う場所により、入る引数が変化する。

リレーの結果を出力する関数を作成します。
１位は金メダル、２位は銀メダル、３位は銅メダル、**４位以降にはその他**の人を出力させる関数を作成したい。このような時に、レスト構文を使用することができます。

```js
function raceResults(gold, silver, bronze, ...rest) {
    console.log(`1位：${gold}さん金メダルです。！`);
    console.log(`2位：${silver}さん銀メダルです。！`);
    console.log(`3位：${bronze}さん銅メダルです。！`);
    console.log(`その他：${rest}さんお疲れ様です。！`);
}

raceResults("太郎","次郎","三郎","四郎","五郎")
```
1. リレーの結果raceResultsという関数を作成します。
2. １位は金メダル、2位は銀メダル、3位は銅メダル、4位以降はその他として出力したいとします。
2-1. それぞれ、gold、silver、bronzeと３つの変数を作成します。
2-2. 4位以降の人に関しては全て同じ出力として出したいので、...「ドット３つ」でそれ以降という意味で付け、restという変数に保存します。

3. テンプレートリテラルを使用し、それぞれの変数に対応した出力を作成します。

```text:出力結果：
1位：太郎さん金メダルです。！
2位：次郎さん銀メダルです。！
3位：三郎さん銅メダルです。！
その他：四郎,五郎さんお疲れ様です。！
```
「...rest」 と書いた中に、入力した４人目以降の値「四郎、五郎」が挿入されていることを確認できます。

## まとめ：

:::note info
レスト構文とスプレッド構文の違いを理解し、
それぞれの使い分けをイメージすること。

・レスト構文は　「集めるイメージ」
・スプレッド構文は「広げるイメージ」

:::
山奥SEOで最低限知っておくべき基礎知識と作業の流れ【Qiitaで学ぶ】

## 山奥SEOとは？最低限知っておくべき基礎知識と作業の流れ
![YAMAOKU-SEO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749668/70be3f69-f0a8-ef73-8cf6-c3c120035244.png)
### 山奥SEOとは？
山奥SEOは、検索ボリュームが非常に少ない（0〜100程度）のキーワードを狙うSEO手法で、主な目的は、競合が少ないキーワードで検索エンジンの上位表示を狙うことであると私は定義している。
つまり、他のサイトがターゲットにしていないニッチなキーワードを選ぶことになるため、最低限の労力で上位表示が可能となる。

### 山奥SEOは初心者こそ注目するべき
山奥SEOは初心者でも取り組みやすい考え方だが、まずは内部SEOと外部SEOといったSEOの基本的な概念を理解するところから始めることを私は推奨する。サイト内部の最適化、外部リンクの作用などは一通りしておく方が良いだろう。

### どこから手をつけるか
山奥SEOにおける最低限のステップは次のようなもの。
1. **キーワードリサーチ**
ここではなるべく検索ボリュームが少ないキーワードをピックアップ。
2. **コンテンツの最適化**
ピックアップしたキーワードをわかりやすく解説した超専門的なコンテンツを作る。
3. **メタタグの設定**
わかりやすいタイトルタグと見出しを設定する。
4. **内部リンクの設定**
サイト内で関連ページへ内部リンクをはる。
5. **外部リンクの獲得**
他サイトからリンクが得られるよう引用されやすいフォーマットで記載する。

### 山奥SEOライティング
山奥SEOライティングとは、Google検索エンジンに向けて、徹底的に専門性を訴求する手法であることを先程お伝えした。ポイントは、ニッチなキーワードにも関わらず、あり得ないほどマニアックな視点からとてつもなく詳しく掘り下げる手法であると私は考える。月間検索数が0～10といった通常であれば誰も手を出さないようなテーマのコンテンツを具体的で読みやすく、かつ丁寧に見出しを区切り、検索意図に寄り添った文章を作った上で、更にリストやテーブル、グラフや画像などを活用しながら強烈な超高クオリティに仕上げるランディング方法だ。

### 最低限で最高のコンテンツを作る
最低限のキーワードリサーチとSEO施策だけで済むとはいえ、コンテンツは高クオリティなものをユーザーに提供することを私は心がけている。つまり、SEOであろうと山奥SEOであろうと、その山は高く険しく、近道などは存在しないのだ。
とりあえず動けばいい人向けDiscordBotの作成手順（python）

とりあえず難しいのいいから動けばいいや的な人向けのDiscord Bot作成手順

# １．Discord Botの作成

https://discord.com/developers/applications

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3432250/ef51dfef-6800-0503-182b-900eecb3e13c.png)

New Applicationを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3432250/54e99d11-fc98-3444-f1dc-496aa94cee49.png)
このBotのTOKENを取得



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3432250/c80b05b8-1a96-0f88-90d6-fce67f94388b.png)
Botという項目のPrivileged Gateway Intentsをすべて選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3432250/03a8ebd7-938b-43de-51fd-1f7056606b9d.png)

OAuth2という項目に移動
OAuth2 URL Generatorの
・SCOPESを「bot」
・BOT PERMISSIONSを「Adminster」
にチェックを入れる

### そのまま下にスクロールするとリンクがあるのでコピーして、検索する

以下のような画面が出る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3432250/ebeb3697-6564-15fd-368e-56cfb063ddf4.png)
ここで導入したいサーバーを選択する
これでBotの導入は完了。

# ２．Botをコードで動かす

サンプルコード
``` sample.py
import discord


TOKEN = "Your_DiscordBot_TAKEN"
channel_ID = "Channel_ID"#チャンネルを１つ指定する場合


####ここら辺はおまじないと思ってもいい

intents = discord.Intents.all()
#↑上記でPrivileged Gateway Intentsをすべて選択したのはこう書くのが楽だと考えてたから

intents.messages = True

client = discord.Client(intents=intents)


####

@client.event
async def on_ready():
    print('ログインしました')
      

@client.event
async def on_message(message):

    if message.author.bot:#Botのには反応しない
        return

    if message.channel.id != int(channel_ID):#指定のチャンネルのみに反応
        return    
    
    #なにかメッセージが来た場合に「こんちわ」返す
    await message.channel.send("こんちわ")

client.run(TOKEN)  
```

# ３．どんなふうになるか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3432250/4083d033-fc21-84bd-442b-44debcc71631.png)

指定のチャンネルでなにかテキストを打つと「こんちわ」と応答されます。
別のチャンネルでは何も反応しません。


# おまけ

指定の語が来た場合返す
```sample.py
if message.content == 'はろー':
        await message.channel.send("ちっすちっす")
```
キーボード入力の自動化対応

## 概要
本記事では、キーボード入力を自動化する方法を記載します。
また、簡単なGUIツールのテスト自動化方法も合わせて記載する。

### キーボード入力の自動化を行いたい状況
まず、キーボード入力の自動化に関して、どのような場合に使用するかをまとめました。
おそらく、GUIツール関係のテスト時に使用するかなと思います。
→ ユーザの操作をパターン化し、テストに落とし込む。

・GUIツールの自動化テストを作成するとき
・Windowsのショートカットキーを使用するとき

### おすすめのライブラリ
今回は、キーボード自動化を行うパッケージを２つ紹介します。
それぞれ特徴が異なるため、使用用途に合わせて選択しましょう。

#### Robotクラス

keyPress関数を使用することで、キーボードを1度押したことになる。
また、keyRelease関数を記載しなくても、問題なく動作していたが、お作法として「入力 → 解除」はひとまとめに考えたほうが良さそうだ。
```
import java.awt.Robot

val robot = Robot()

// 常に100ミリ秒の待機時間を設ける
// 目視でのキーボード入力が確認できる(これがないと一瞬で入力されてしまう)
robot.delay(100)

// キーボードの入力
robot.keyPress(KeyEvent.VK_ENTER)
// キーボードの解除
robot.keyRelease(KeyEvent.VK_ENTER)
```


#### Sikulixツール
Robotクラスとは異なり、事前に設定したキーボード入力処理を外部プロセスとして呼び出して使用する。また、Robotクラスとの差別化として、画像認識を使用できる。

■手順
①Sikulixツールのダウンロード
②キーボード入力をまとめSikulixフォルダ作成
③呼び出し用のバッチファイル作成
④外部プロセスの呼び出し処理追加

また、使用方法に関しては、ネット上にいくらでも存在するため、本記事では割愛する。
③呼び出し用バッチファイル作成のみ、メモとして残しておく。

```
cd /d %˜dp0
set filePath=..\sikulixide-2.0.5.jar
set proPath=..\sikulix\○○.sikuli
call java -jar %filePath% -r %proPath%

```

### まとめ
基本的には、Robotクラスを使用するとよい。
Sikulixに関しては、キーボード入力に対応していないボタンの処理があれば、候補に入れてる程度で考えていい。

また、私の場合は出力結果(画像)の比較方法を調べた際に、Sikulixに行き着いた。
~~結局は、Sikulixの画像認識が安定しなかったため、「javax.imageio.ImageIO ライブラリ」を使用し、ピクセルごとのが画像比較で対応しているが。。。~~
OACのダッシュボード・フィルタでラジオボタンを使う

# はじめに
OAC（**Oracle Analtyics Cloud**）には、ダッシュボード・フィルタという特殊なビジュアライゼーションがありますが、これを使ってラジオボタンを作ってみたいと思います。
※ OAC May 2024 Updateを使用しました。

# ダッシュボード・フィルタ
用意したワークブックです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/312ff8a1-6ce8-6b21-4c49-0fe2e8b2ebbe.png)

ビジュアライゼーションを表示し、「ダッシュボード・フィルタ」をキャンバスにドラッグ＆ドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/716f8581-e54f-7eef-0b2a-ec47d654cd94.png)

データを表示し、項目をダッシュボード・フィルタにドラッグ＆ドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/e079ba40-c23e-7f2b-0e24-4e917c6ec17c.png)

## デフォルトの動作
デフォルトでは、複数選択可能なリストが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/fea3e357-d8ef-9874-8d9f-c3f03dbc0bc1.png)

## ラジオボタンは作れるのか？
ダッシュボード・フィルタのプロパティを表示します。
続いて、フィルタ・コントロールの中からフィルタ・タイプを変更します。
デフォルトの「リスト」から「インライン・リスト」に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/264ec96e-89ba-7a91-1d1d-81cdaeddce02.png)

ダッシュボード・フィルタのリストコントールがチェックボックスになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/8b7f495b-d3dc-0d37-e2a0-271eb514f70a.png)

複数選択をオフにすると、ラジオボタンになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/8871a05f-54d3-5f19-d741-5e73600abcc3.png)

# 完成
完成したワークブックです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/ca6792d0-8ee9-7f4d-461d-4abe46507783.png)
【Flutter】StatusBarの色変更をAndroidとiOS両方に対応させる

## 問題点
こちらがよくあるStatusBarの色の変更方法だと思います。
しかし、この方法だとAndroidには反映されるものの、iOSには反映されません。

```dart
SystemChrome.setSystemUIOverlayStyle(
    const SystemUiOverlayStyle(
      statusBarColor: <任意のステータスバーの色>,
    ),
);
```

## 解決方法
カスタムAppBarを作成し、Stackを使ってStatusBarの高さ分のContainerをAppBarに被せる

```dart
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
  const CustomAppBar({super.key});

  @override
  Widget build(BuildContext context) {
    final statusBarHeight = MediaQuery.of(context).viewPadding.top;

    return Stack(
      children: [
        AppBar(),
        // StatusBarサイズの色付きContainer
        Container(
          width: double.infinity,
          height: statusBarHeight,
          color: <任意のステータスバーの色>,
        ),
      ],
    );
  }

  @override
  Size get preferredSize {
    return const Size.fromHeight(kToolbarHeight);
  }
}
```
毎日ABC day11【c++】ABC335 A-C問題解説【ACコード付き】

# AtCoder Beginner Contest 335

https://atcoder.jp/contests/abc335

## A - 202
3

与えられた文字列の最後の文字を4に変換して出力する。

与えられた文字列の最後の文字以外を出力し、最後に4を出力する方法をとったが、`pop_back()`で最後の1文字を削り、`push_back()`で4を末尾に追加する方法などもあったらしい。

```cpp
string S;

int main()
{
	cin >> S;
	for (int i = 0; i < S.size() - 1; i++)
	{
		cout << S[i];
	}
	cout << "4" << endl;
	return 0;
}
```

## B - Tetrahedral Number
整数 $N$ が与えられます。

非負整数の組 $(x,y,z) $であって$ x+y+z≤N$ を満たすものを辞書順で小さい方から順番に出力せよ、という問題。

小さい桁から昇順にfor文で回し、3桁の合計が $N$ を超えないように注意。

```cpp
int N;

int main()
{
	cin >> N;
	for (int i = 0; i <= N; i++)
	{
		for (int j = 0; j <= N; j++)
		{
			for (int k = 0; k <= N; k++)
			{
				if (i + j + k > N) continue;
				cout << i << " " << j << " " << k << endl;
			}
		}
	}
	return 0;
}
```

## C - Loong Tracking
1マスずつ龍を動かしていって、指定の龍の体のパーツの位置はどこにあるか、座標を出力する問題。

最初は座標を配列で保持していたがWAが続き、dequeに救われた。前にも後にも追加できて、indexで各要素に迅速にアクセス可能。さすがc言語系列！

```cpp
int N, Q, tmp;
deque<pair<int, int>> dragon;
int query_num;
char query_char;

int main()
{
	// 入力
	cin >> N >> Q;
	for (int i = 1; i <= N; i++)
	{
		dragon.push_back(make_pair(i, 0));
	}
	int move_count = N;
	for (int i = 1; i <= Q; i++)
	{
		cin >> query_num;
		if (query_num == 1)
		{
			move_count++;
			cin >> query_char;
			auto x = dragon[0].first;
			auto y = dragon[0].second;
			if (query_char == 'R') dragon.push_front(make_pair(x+1, y));
			else if (query_char == 'L') dragon.push_front(make_pair(x-1, y));
			else if (query_char == 'U') dragon.push_front(make_pair(x, y+1));
			else dragon.push_front(make_pair(x, y-1));
		}
		else
		{
			cin >> tmp;
			cout << dragon[tmp - 1].first << " " << dragon[tmp - 1].second << endl;
		}
	}
	return 0;
}
```
既存のpkgファイルを展開し再度pkg化する方法


特殊な事情で「Distribution.xml」を書き換えなければいけない場合などに。
```bash
# パッケージの展開
pkgutil --expand /path/to/package.pkg /path/to/output_dir
```

```bash
# 再度パッケージ化
pkgutil --flatten /path/to/output_dir /path/to/new_package.pkg
```
cscの作法 その504

# 概要
cscの作法、調べてみた。
wpf見つけたので、msbuildでコンパイルしてみた。

# 参考にしたページ

https://qiita.com/yosgspec/items/edb3f22741ea362cea1a

# 環境
windows11

# ビルドを書く。

```

<Project DefaultTargets='Build' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
	<PropertyGroup>
		<Configuration>Debug</Configuration>
		<Platform>AnyCPU</Platform>
		<RootNamespace>Test</RootNamespace>
		<AssemblyName>WpfApp2</AssemblyName>
		<OutputPath>.\bin\Debug\</OutputPath>
	</PropertyGroup>
	<ItemGroup>
		<Reference Include='System' />
		<Reference Include='System.Xml' />
		<Reference Include='WindowsBase' />
		<Reference Include='PresentationCore' />
		<Reference Include='PresentationFramework' />
		<Reference Include="System.Xaml">
			<RequiredTargetFramework>4.0</RequiredTargetFramework>
		</Reference>
	</ItemGroup>
	<ItemGroup>
		<ApplicationDefinition Include="app2.xaml" />
		<Page Include="index2.xaml" />
		<Compile Include='main2.cs' />
	</ItemGroup>
	<Import Project='$(MSBuildBinPath)\Microsoft.CSharp.targets' />
	<Import Project='$(MSBuildBinPath)\Microsoft.WinFX.targets' />
</Project>


```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/8af95e40-222f-ffea-f80c-99a981f1b732.png)


以上。
16ビット漢字ROMのフォント半角数字を作って遊ぶ。





![o_coq158.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ad8c6aa2-c079-d612-7cc1-87acc3eba7d0.jpeg)


```

0x0000, 0x0000, 0x3800, 0x4400, 0xa200, 0xa200, 0x9200, 0x9200, 
0x9200, 0x8a00, 0x8a00, 0x4400, 0x3800, 0x0000, 0x0000, 0x0000, //0
0x0000, 0x0000, 0x1000, 0x3000, 0x5000, 0x1000, 0x1000, 0x1000, 
0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, //1
0x0000, 0x0000, 0x3800, 0x4400, 0x8200, 0x8200, 0x0200, 0x0400, 
0x0800, 0x1000, 0x2000, 0xc000, 0xfe00, 0x0000, 0x0000, 0x0000, //2
0x0000, 0x0000, 0x3800, 0x4400, 0x8200, 0x8200, 0x0400, 0x3800, 
0x0400, 0x8200, 0x8200, 0x4400, 0x3800, 0x0000, 0x0000, 0x0000, //3
0x0000, 0x0000, 0x0400, 0x0c00, 0x1400, 0x2400, 0x4400, 0x8400, 
0xfe00, 0x0400, 0x0400, 0x0400, 0x0400, 0x0000, 0x0000, 0x0000, //4
0x0000, 0x0000, 0xfe00, 0x8000, 0x8000, 0x8000, 0x7800, 0x0400, 
0x0200, 0x0200, 0x0200, 0x8400, 0x7800, 0x0000, 0x0000, 0x0000, //5
0x0000, 0x0000, 0x3800, 0x4400, 0x8200, 0x8000, 0xb800, 0xc400, 
0x8200, 0x8200, 0x8200, 0x4400, 0x3800, 0x0000, 0x0000, 0x0000, //6
0x0000, 0x0000, 0xfe00, 0x0200, 0x0200, 0x0400, 0x0400, 0x0400, 
0x0800, 0x0800, 0x0800, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, //7
0x0000, 0x0000, 0x3800, 0x4400, 0x8200, 0x8200, 0xc600, 0x7c00, 
0xc600, 0x8200, 0x8200, 0x4400, 0x3800, 0x0000, 0x0000, 0x0000, //8
0x0000, 0x0000, 0x3800, 0x4400, 0x8200, 0x8200, 0x8200, 0x4600, 
0x3a00, 0x0200, 0x0200, 0x4400, 0x3800, 0x0000, 0x0000, 0x0000  //9


```
16ビット漢字ROMのフォント「日付」/「時刻」/「温度」を作って遊ぶ。



![o_coq157.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/4057ac1d-434d-3e64-df6f-0abb53c8a073.jpeg)


```

0x0000, 0x3ff8, 0x2008, 0x2008, 0x2008, 0x2008, 0x2008, 0x3ff8, 
0x2008, 0x2008, 0x2008, 0x2008, 0x2008, 0x2008, 0x3ff8, 0x0000,//日 
0x0000, 0x0010, 0x0410, 0x1810, 0x3010, 0x53fc, 0x1010, 0x1110, 
0x1090, 0x1050, 0x1010, 0x1010, 0x1050, 0x1030, 0x1010, 0x0000,//付
0x0000, 0x0000, 0x0080, 0x07f0, 0x7080, 0x5080, 0x5ffc, 0x5000, 
0x7010, 0x57f8, 0x5010, 0x5210, 0x7150, 0x0030, 0x0010, 0x0000,//時 
0x0400, 0x0404, 0x7fd4, 0x0414, 0x0814, 0x1094, 0x0b14, 0x0c14, 
0x3094, 0x4314, 0x0c14, 0x3204, 0x4104, 0x0094, 0x000c, 0x0000,//刻
0x0000, 0x43f8, 0x2208, 0x13f8, 0x4208, 0x23f8, 0x1000, 0x0000, 
0x13f8, 0x12a8, 0x22a8, 0x22a8, 0x22a8, 0x42a8, 0x47fc, 0x0000,//温
0x0080, 0x1ffc, 0x1000, 0x1220, 0x2ff8, 0x2220, 0x23e0, 0x2000, 
0x2ffc, 0x2410, 0x4360, 0x4080, 0x4160, 0x4618, 0x0806, 0x0000 //度


```
kotlin × Iciqlでinner joinを行う方法

# はじめに
Javaであれば公式ドキュメントに例があります。
http://iciql.com/examples/#inner-join-statements
自分は同じことをkotlinで実装する際に嵌ったためメモとして残します。

# 実装
例えば1個目の例のようにCustomerテーブルとOrderテーブルをinner joinしてCustomerの全カラムを取得したい場合は
```
val customersWithLargeOrders =
    db.from(c).
    innerJoin(o).on(c.customerId).is(o.customerId).
    where(o.total).greaterThan(BigDecimal("500.00")).
    groupBy(c.customerId).select();
```
とすればOKです。

ですがよくあるパターンで「全てのテーブルにIDという名前のカラムが存在する」状況（※）だとこの書き方だと"Column 'id' in field list is ambiguous"などのエラーが発生し失敗します。

※他に主キーとして相応しいカラムがあるならidカラムを作るよりもそっちを主キーにした方が良いと思います。

Iciqlにはasを使ってカラム名を一時的にリネームする方法が多分ありません。ですので公式ドキュメント2つ目の例
```
List<CustOrder> orders =
    db.from(c).
    innerJoin(o).on(c.customerId).is(o.customerId).
    where(o.total).lessThan(new BigDecimal("500.00")).
    orderBy(1).
    select(new CustOrder() {{
        customerId = c.customerId;
        orderId = o.orderId;
        total = o.total;
    }});
```
のように必要なカラムだけを抜き出すためのクラス（を継承した匿名クラス）をselectに渡す必要があります。
例で波括弧が2重になっているのは誤字ではなく匿名クラス内にイニシャライザがあるということです。

これをkotlinで再現する場合、まずselectに渡すためのクラスは
```
open class Hoge() {
    var fuga : Int = 0
}
```
のように
- openをつける（でないとイニシャライザでメンバ変数を参照できない）
- valではなくvarにする（イニシャライザで代入が行われるため）
必要があります。

上の例で2重括弧となっていた箇所は
```
{
    init {
        //ここに代入処理を書く
    }
}
```
とします。

# 終わりに
正直ほぼkotlinの文法の話という気がしますが、普段Javaばかり使っていてkotlinについて理解していないことが多いこと及びJavaでも普段イニシャライザは全然使わないのでそもそもどう調べれば良いのか分からず苦労しました。
Iciqlについては日本語資料が少ないので同じようにkotlin × Iciqlで悩んでいる人たちのために時々メモを残していきたいと思います。
エンジニアのための退職完全ガイド：スムーズなキャリアチェンジを実現

転職、独立、休職など、様々な理由で退職を考えることは誰にでもあるでしょう。しかし退職を決意すると、具体的な手続きやスケジュールが分からず不安になる方も多いのではないでしょうか？実際に私もエンジニアをしていて3社で退職した経験があり、退職回数が増えることで慣れてきて不安は減ります。ただ最初の退職では、**これで人生が詰むのではないか**と恐怖していたことを今でも覚えています。

そこで今回は3度の退職経験のある私が、退職までの流れを徹底解説します。会社への退職表明から、退職後の手続きまで必要事項を分かりやすく説明します。さらにスムーズな退職のためのポイントも紹介するので、ぜひ参考にしてください。

## 退職までの事前準備
![Preparations-to-be-made-before-filing-for-retirement.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784196/9bb74647-cb96-b46b-361d-004a701c18ce.jpeg)

まず実際に退職のアクションを起こす前に、以下のことについて準備が必要です。

- **退職すべきかどうかを検討する**
一時的な会社への不満から、衝動的に退職を決めてしまうと、後々大きな損失を被るリスクがある

- **次のキャリアプランを立てる**
エンジニアの場合は大きく分けて、他社への転職とフリーランスへの独立の2つの選択肢が考えられる

- **家族の理解を得る**
退職は自身の人生に大きな影響を与えるだけでなく、家族にも大きな影響が及ぶ

[>> 各準備について詳しくはコチラ！](https://taishi-official.com/2024/04/24/2190/#toc2)

## 退職の申し出から完了までの流れ
![Process-from-Retirement-Declaration-to-Completion.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784196/f1714a15-d35f-5950-dd68-0dc13d17f25c.jpeg)

上記の準備が完了した方は、実際の退職する手続きへと入っていきます。退職に必要な作業を、以下の4STEPに分解して紹介します。

1. **会社に退職の意思表示をする**
退職を申し出るタイミングとしては、退職予定日の2か月前に申し出るのがおすすめ

2. **作業の引き継ぎ**
完全に後任者に引き継ぐのはとても難しいですが、「飛ぶ鳥跡を濁さず」の精神でがんばる

3. **お世話になった人へのご挨拶**
会社を離れた後は基本的には顔を合わせる機会がなくなるので、あまりにも神経質にすべての人にご挨拶を済ませなくてもよい

4. **会社からの貸与物の返却**
通常であれば退職手続きを所管する事務担当者から、返却が必要な物品リストや返却の手順などについて連絡がある

[>> 退職手続きに関する詳しい解説はコチラ！](https://taishi-official.com/2024/04/24/2190/#toc6)

**※注意※**
こちらで紹介する退職の流れは、あくまで一般的な場合となります。例えばブラック企業と呼ばれる労働環境が劣悪な会社に勤めていたり、上司や同僚とのトラブルで人間関係が悪化していたりする場合は、以下を参考にされてください。

[>> ブラックな環境で退職を認めてもらえない場合](https://taishi-official.com/2024/04/24/2190/#toc5)

## 退職後に必要な行政手続き
![Administrative-procedures-required-after-retirement.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784196/a80a9b4c-7d84-5c20-7963-6972dcdba7a7.jpeg)

最後に退職後に必要な行政手続きについて、ご説明します。退職後に必要となる手続きは、以下の3つです。

- 国民健康保険の切り替え
14日以内を期限に、居住する市区町村の市役所や役場にある国保窓口にて切り替え手続き

- 年金の移行手続き
国民健康保険の切り替えと合わせて、年金窓口にて手続き

- 失業保険の受給申請
失業保険は自己都合退職の場合、最初の入金までに3か月ほどかかるので注意

[>> 各種申請手続きに関してはココを確認！](https://taishi-official.com/2024/04/24/2190/#toc11)

## まとめ
今回は退職をお考えの方に向けて、退職準備～退職後までの一連の流れを私の実体験を踏まえながらご紹介させていただきました。これからの時代は終身雇用ではないので**退職することがリスクではなく、退職をしたことがないほうがリスクとなるような時代**です。

初めての退職は「自分の人生が終わるんじゃないか」と不安になりますが、**退職したくらいでは人生は終わらない**ので安心してください。この記事に私の退職に関するノウハウを詰め込んでいるので、ぜひご参考にしていただければと思います。

### おまけ

https://qiita.com/taishi_will_be/items/70a8ce8938944286b487

https://taishi-official.com/changing-engineer/

<strong>＼Follow me／</strong>

- X（旧Twitter）：https://x.com/taishi_it_blog
- Instagram：https://www.instagram.com/taishi_will_be/
- YouTube：https://www.youtube.com/@Engineer_ILLBE
- TikTok：https://www.tiktok.com/@taishi_will_be
- note：https://note.com/taishi_wii_be/

<br>

最後にいいねお願いします:thumbsup:
開発をさらに効率化する VS Code Chat Extensions

# はじめに

GitHub Copilotで相当開発が効率化できるようになりました。各種データや体験ブログなんかもたくさんありますが、個人的にはGitHub Copilot Chat無しの開発はもうあまり考えられません。同じIDE上でシームレスにサポートしてもらえるのって本当に良いですよね。

と、先日の以下の情報がでてきました。VS Code Chat Extensionsを使うことで、GitHub Copilot Chatをさらに拡張できるとのこと。今回は自前のChatアシスタントを作って、こういう風に使えるのでは、という話を書きたいと思います。

https://code.visualstudio.com/api/extension-guides/chat


:::note warn
注意
VS Code Extensionの Chat API と Language Model APIは、2024 年 7 月の VS Code 安定版リリースで完成する予定とのことです。そのため、本記事の実装コード部分については変更が発生する/している可能性があります。またそれまではVS Code Insider版を使わないと動作確認もできません。
:::

# できるようになること

プロジェクト標準などの独自のチェックシートをもとにした実装レビューを、自前で用意したChatアシスタントに随時レビューさせることができるようになります。もちろん他にもWebベースのRAGだとかにも使えたりと、色々と使い道はあるかと思いますが、まず思いついたのがこれです。

チェックの内容自体はとりあえずの動作確認のために超適当です。こんなチェックはないだろ…、っていうのはご愛敬として、コードを実装中に任意のタイミングで GitHub Copilot にチェックシートベースのレビューを実施させることができます。

以下の通り @iruka で独自のアシスタントを呼び、/review でレビューを依頼、 #file: を使ってチェックしたい開発中のソースコードを指定しています。（アイコンはDALLEで作成しました。つぶれて良く見えませんが・・）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/977156/fff449e7-7930-ca32-93ad-cecfcdd918e0.png)

静的解析として、機械的にコード解析できる部分はこれまで通り実施した上で、人間系でチェックしていた独自レビューポイントなんかを生成AIにまかせられるのはとても良いですよね。

# 実装にあたって

サンプルで公開されている @cat のアシスタントをベースにしました。このサンプルは @cat とコマンドの使い方、初期設定など必要なものが大体入っていますので、これをもとに改造していきます。

https://github.com/microsoft/vscode-extension-samples/tree/main/chat-sample

例えば /review というキーワードが欲しければ、request.commandで判別します。

```typescript
if (request.command == 'review') {
            stream.progress('実装チェックリストを確認しています。');
```

また #file: でのファイル指定からファイルの内容を取得するためには、request.referencesを使います。reference.id が 'vscode.file'であることを確認したうえで、テキスト情報を読み込むことができます。以下の例ではfileで指定された複数データを1つのtexts配列に入れていますが、この辺はお好きなようにという感じです。

```typescript
const references = request.references
const texts = [];

for (const reference of references) {

    // #fileの場合
    if(reference.id === 'vscode.file'){
    
        // ファイルの内容を取得
        const value = reference.value as vscode.Uri;
        const path = value.path;
        const file = vscode.Uri.file(path);
        const document = await vscode.workspace.openTextDocument(file);
        const text = document.getText();

        // 内容をつめる（本当はファイル名とかも入れたほうがよい）
        texts.push(text);
    }
}
```

その上で、システムプロンプトでチェックする内容をいれていきます。
```typescript
const system_pronpt = `\
あなたはプロジェクト標準化エンジニアです。入力されるユーザコードに対して、以下のチェックシート内容の各項目についてレビューし回答してください。

### チェックシート
1. ほげほげ
2. ふがふが
```
このあたりは通常のプロンプトです。サンプル回答とかもいれて精度をあげていきます。

ちなみに実装チェックリストの情報それ自体は、上述みたいにChat Extension の内部に包含してしまってもいいですが、やっぱりサーバサイドにおいて取得する方法の方がベターかなと思います。なお、サーバサイドに置く場合は認証も重要なポイントかと思います。VSCode Extensionsで認証情報を扱う場合は以下も参考にしてください。

https://qiita.com/shyamagu/items/c0b8733903bacd062cd9

# おわりに
本記事では、VS Code Chat ExtensionsをつかってGitHub Copilot Chatを拡張し、レビューチェックシートをベースにプログラムをレビューさせる独自アシスタントについて紹介しました。

プルリクエストのタイミングなどで生成AIにレビューさせるのももちろんアリだと思いますが、今回のようにChat形式で任意のタイミングで実装レビューをかけることで、さらに品質向上に貢献するんじゃなかろうかと思います。

他にも色々な用途が考えられそうですが、取り急ぎ自前のCopilot ChatアシスタントがVS Code上で動くようになりましたということでまずはの1パターンのご紹介でした。
開発業務において、生成AIをどういう風に何でどう組み合わせて使うと良いのか、という観点で今後も抑えていきたいと思います。
運用中のOutSystemsアプリのEntityにUnique制約のついたAttributeを追加したい

## この記事のゴール
運用中のシステムのEntityにUnique制約を付けたAttributeを追加する。

## 発生した現象
運用中のEntityに新しくUnique制約が付いたAttributeを追加する必要が生じた。
ここではCompanyに新しくUnique制約を付けたCodeを追加する。

まず、EntityにAttributeを追加して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796185/a24c0dfd-eb6f-6fae-2ff5-ce6202fd45fd.png)

そのあと制約を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796185/28578b7f-9bfb-fe14-26f5-79f10fee850f.png)

Publishするが、一意制約が発生してしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796185/8189c952-e7fa-f384-dc55-159ff10eea50.png)

すでにレコードが存在しているので、デフォルト値「空値」を複数のレコードに設定しようとして一意制約違反が発生している。

## 試したこと
1. デフォルト値が一意になるように設定する
1. Unique制約を後から設定する


### デフォルト値が一意になるように設定する

ぱっと思いつく方法は

1. GUIDを生成して格納する
残念ながら安直にサーバアクションを設定することができない模様。裏でSQLに変換されるのだろうし、デフォルト値に何が設定できるのか少し調べただけではわからなかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796185/d42623b7-7fd4-f1c8-db31-aaced0308991.png)

1. 該当レコードのIDを文字列に変換して格納する
Guidと同じ理由で断念。

すぐには解決できそうにないので2つ目の施策を考える。

### Unique制約を後から設定する

既視感、よく考えたらPythonのDjangoでよくやっていた方法。

1. 既存Entityに新しいAttributeをUnique制約なしに追加する
まずはDataTypeとLength、IsMandatoryを設定しUnique制約を付けずにPublishする。


1. 新しいAttributeに一意な値を設定する
既存のレコードに対して新しく追加されたAttributeに一意な値を設定するタイマーを作成する。
ここではCodeというAttributeに同レコードのIDを設定することで一意性を担保している。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796185/59af3f18-8ef8-11dd-96da-226dc667ff77.png)
タイマーを実行し、一意の値を設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796185/a034d2cc-722e-f110-1381-22d861c1a8cb.png)


1. 新しく追加したAttributeにUnique制約を付加し、Publishする

## まとめ
運用中のシステムのすでにレコードが存在するEntityにUnique制約を付けたAttributeを追加必要が出た場合には、以下の手順を実施することで実現できる。

1. 既存Entityに新しいAttributeをUnique制約なしに追加する
1. 新しいAttributeに一意な値を設定する
1. 新しく追加したAttributeにUnique制約を付加する

本番環境にLifeTimeで配置して終了とはいかず、タイマーを動かしてから再度本番への変更が必要となる。本番適用のためには、事前の十分な計画とテストが必要。
AmazonLinux2にffmpegをインストールする方法

# インストール方法

まずはyumをアップデート。

```bash
sudo yum -y update
```

必要なモジュールをインストール

```bash
sudo yum install -y git bzip2 tar gcc make openssl-devel readline-devel zlib-devel wget xz xz-devel
```

適当なディレクトリを作成しffmpegをダウンロード。解凍する。

```bash
mkdir ffmpeg
cd ffmpeg
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar -xf ffmpeg-release-amd64-static.tar.xz
```

シンボリックリンクを作成。必要なければtar.xzファイルを削除

```bash
sudo ln -s /home/ec2-user/ffmpeg/ffmpeg-7.0-amd64-static/ffmpeg /usr/bin/ffmpeg
rm ffmpeg-release-amd64-static.tar.xz
```

# 確認

ffmpegのpathを確認

```bash
 which ffmpeg
# /usr/bin/ffmpeg
```

下記コマンドでバージョンが表示されたらOK。

```bash
ffmpeg -version
```

# 使い方

動画の情報を調べる。

```bash
ffmpeg -i input.mov
```

movをmp4に変換する。

```bash
ffmpeg -i sample.mov sample.mp4
```

# ffprobe

ffprobeにシンボリックリンクを作成

```bash
sudo ln -s /home/ec2-user/ffmpeg/ffmpeg-7.0-amd64-static/ffprobe /usr/bin/ffprobe
```

# Sample

ビデオファイルを圧縮するためのffmpegコマンドの例

```bash
ffmpeg -i input.mp4 -vcodec libx264 -crf 23 -preset veryslow -acodec aac -b:a 128k output.mp4
```

**-crf 23 :** 圧縮の品質レベル（数値が低いほど品質が良く、23はバランスが取れています）。
**-preset veryslow :** プリセットが遅いほど、同じ画質でより良い圧縮ができます。
windows11 miracast anycast


## hp x2 g2 なので　解像度が　3000x2000 以上なので　普通のTVには　HDMIケーブルでは映りません

https://www.youtube.com/watch?v=TQRmcyDY47g

![Photo Marker_20240604_104201.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/962f9867-6d25-51c1-4fbc-ea9611c9bd0a.jpeg)


こんなふうにできあがります

https://www.youtube.com/watch?v=GE3Y_Ztik-w


## 本論です

![Photo Marker_20240604_070701.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/f114d9d7-0313-9608-af25-56c8f1fa790a.jpeg)


と古いTVのLANポートに有線LANをつなぎ　待つと


![Photo Marker_20240604_070844.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/9a5d0069-8c67-cc6e-5e4e-718cb1355d21.jpeg)

まんなかのmiracastがインターネットとつながります


windows11 で　wifiの接続先として　miracastを選びます
![Photo Marker_20240604_071216.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/df9390a3-4799-84b0-8ee3-5cf827952391.jpeg)

すると　下図のように
一番左のwindows11がmiracastと結ばれます


4
![Photo Marker_20240604_071508.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/ad8b7601-8197-a842-aa28-ee9e1bb6b06e.jpeg)



win11で　設定ー＞マルチディスプレイ
-5
![Photo Marker_20240604_073009.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/3d65bb7e-8059-a7aa-108e-0ea8d8d8be0e.jpeg)

つづいて　ワイヤレスディスプレイを選びます
-4
![Photo Marker_20240604_072849.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/95f1f211-333b-cd9b-bc8c-3aaba71de81e.jpeg)


すると
-3
![Photo Marker_20240604_072746.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/62872538-06d0-ec78-c66d-9632df89e149.jpeg)
miraが出てくるのでここをクリックします



-2
![Photo Marker_20240604_072641.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/655c0d38-77e3-4e04-ffd5-f8d3568deb5a.jpeg)
こういうふうに　複製がTV画面にでます


youtubeもTVでみれますね
-1
![Photo Marker_20240604_072558.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/9e16710b-bf3f-6a3f-e568-61c6cf040369.jpeg)













## X-1)　有線LANをつながなくともいけることが　わかりました



## X-２)　今は

まず　windows　１１を起動します

つぎに　miracastいれたままTVのスイッチをいれます


miraだけつけて　TVのスイッチをONにして　１分ほど放置すると

mira自体が学習したのか

![１.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/17d23d5d-6e5f-6da5-fd04-9fffcc470e7f.jpeg)

なってます。
MIRAが勝手に　本物のWIFIルーターにつながった感じです


つぎは　いきなり
パソコンの
![Photo Marker_20240607_074922.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/1e678d84-37d8-f0e9-d166-3f86eabd0fd4.jpeg)
の画面から
wirelessディスプレイにつなぐだけで
OKになりました






## X-3)　anycast m9 plus の場合

PCモニターにくっつけても手法は一緒で



win11を起動させてから
anycast をPCモニターにくっつけると


![Photo Marker_20240611_045727.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/d5b2fdab-63ed-d9ed-3fc2-71cfa9411e39.jpeg)

がでます
    　
ｗｉｎ１１で　ディスプレイを選び

![Photo Marker_20240611_045750.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/12dc3af4-d869-e3e2-18fe-eea1172221f8.jpeg)

それからワイアレス

![Photo Marker_20240611_045846.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/45e5da5d-211d-78fc-a541-d9ad03c347ca.jpeg)


![Photo Marker_20240611_045644.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/bb8d2a6d-993a-03fa-6b4c-752bfc627511.jpeg)
UbuntuにRabbitMQを簡単にインストールする手順

# RabbitMQをUbuntuにインストールする手順

RabbitMQをUbuntuにインストールするには、以下の手順を実行します。これには、必要な依存関係のインストールとRabbitMQのインストールが含まれます。

## 1. 依存関係のインストール
RabbitMQはErlangランタイム環境に依存しています。まず、Erlangをインストールします。

```bash
sudo apt update
sudo apt install -y erlang
```

## 2.RabbitMQのインストール

```bash
# RabbitMQの公開鍵をインポート
curl -fsSL https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey | sudo apt-key add -

# リポジトリの追加
sudo tee /etc/apt/sources.list.d/rabbitmq.list <<EOF
deb https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu/ $(lsb_release -cs) main
EOF

# パッケージリストの更新
sudo apt update

# RabbitMQのインストール
sudo apt install -y rabbitmq-server
```

## 3. RabbitMQの起動と有効化
インストール後、RabbitMQサーバーを起動し、自動起動を有効にします。
```bash
sudo systemctl start rabbitmq-server
sudo systemctl enable rabbitmq-server
```

### 5. ファイアウォールの設定
管理インターフェースにアクセスするためにファイアウォールの設定を行います（必要に応じて）。

```bash
sudo ufw allow 15672
```

### 6. 管理インターフェースへのアクセス
ウェブブラウザで http://localhost:15672 にアクセスします。
デフォルトのログイン情報はguest/guestです。

これでRabbitMQがUbuntuにインストールされ、使用できるようになります。
さらに詳しい情報や設定については、公式ドキュメントを参照：RabbitMQ Documentation。
UV・マルチUVの備忘録

## UVについて

### UVとは何か

- **UV座標**: 3Dオブジェクトの表面に2Dテクスチャを正確に配置するための座標系です。3D空間の座標がXYZで表されるのに対し、テクスチャの2D空間はUV座標で表されます。
- **UとV**: これらは、テクスチャ画像の縦横の軸に対応します。通常、Uは水平方向、Vは垂直方向を表します。これにより、テクスチャ画像の各ピクセルが3Dモデルのどの部分に対応するかが決まります。

### UVマッピング

- **目的**: 3Dモデルに2D画像（テクスチャ）を貼り付けるためにUV座標を使用します。これにより、モデルの表面に詳細な模様や色を付けることができます。
- **手順**: 3Dモデリングソフトウェア（例えばBlender、Maya、3ds Maxなど）でモデルの各面に対応するUV座標を割り当てます。このプロセスをUV展開（UV unwrapping）と言います。

### UV展開の方法

1. **自動展開**: ソフトウェアが自動的にUVマップを生成する方法。初心者向けで簡単ですが、結果が必ずしも最適でないことがあります。
2. **手動展開**: ユーザーが手動でシーム（seam）を設定し、UVマップをカスタマイズする方法。詳細なコントロールが可能ですが、時間と技術が必要です。
3. **投影法**: 平面、球体、円柱などの特定の形状に基づいてUVマップを生成する方法。

### UVマップの品質

- **ストレッチング（Stretching）**: UVマップが不適切だと、テクスチャが引き伸ばされて見えることがあります。これを避けるために、UV展開時にはストレッチングを最小限に抑えるよう注意します。
- **シームレスな接続**: UVシームの位置とテクスチャのつなぎ目が目立たないようにすることも重要です。

### 応用例

- **ゲーム開発**: キャラクターや環境モデルにテクスチャを貼り付けるためにUVマッピングが広く使用されています。
- **映画とアニメーション**: 詳細なスキンテクスチャや表面の模様を表現するために使用されます。
- **製品デザイン**: プロトタイプや製品のビジュアル化のために、リアルな素材感を表現するためにUVマッピングが利用されます。

マルチUVとは、単一の3Dモデルに対して複数のUVマップを使用する技術です。これにより、同じモデルに対して異なるテクスチャマッピングを適用することができます。以下にマルチUVの詳細を解説します。

## マルチUV
### マルチUVの概要

- **複数のUVセット**: 通常のUVマッピングでは、1つのUVセットが1つのテクスチャマップに対応しますが、マルチUVでは、複数のUVセットを同じモデルに対して定義します。これにより、異なるテクスチャを同時に管理できます。

### マルチUVの利点

1. **複数のテクスチャを使用**: 異なるUVセットを使用することで、同じモデルに対して複数のテクスチャを適用できます。例えば、1つのUVセットはカラーマップ用、別のUVセットはノーマルマップ用というように使い分けることができます。

2. **異なる解像度のテクスチャ**: 各UVセットごとに異なる解像度のテクスチャを使用することができます。これにより、詳細な部分には高解像度のテクスチャを適用し、広い部分には低解像度のテクスチャを適用するなどの最適化が可能です。

3. **特定部分の詳細なテクスチャリング**: 特定のモデル部分に対して、詳細なテクスチャリングを施す際に有効です。例えば、キャラクターの顔には高解像度のテクスチャを、体には別のテクスチャを使用することができます。

### マルチUVの使用例

1. **ゲーム開発**: ゲームモデルにおいて、異なるマテリアルやエフェクトを適用するためにマルチUVが使われます。例えば、キャラクターの表面にはカラーテクスチャを適用し、別のUVセットで法線マップやスペキュラーマップを管理します。

2. **映画とアニメーション**: 高精度なモデルに対して、ディテールを維持しながら異なる質感を再現するためにマルチUVが使用されます。例えば、キャラクターの衣服と肌に別々のUVマップを使うことで、質感の違いを明確に表現します。

3. **建築ビジュアライゼーション**: 建築モデルにおいて、異なる材質（壁、床、天井など）に対して異なるテクスチャを適用するためにマルチUVが利用されます。

### マルチUVの設定方法

- **3Dソフトウェア**: 多くの3Dモデリングソフトウェア（例えば、Blender、Maya、3ds Maxなど）は、マルチUVの設定をサポートしています。各UVセットを個別に編集し、異なるテクスチャを適用することができます。

- **シェーダー**: ゲームエンジンやレンダリングエンジンでは、シェーダーを使って複数のUVマップを参照し、それぞれに対応するテクスチャを適用します。

### UE内でマルチUVを使用する
マテリアルノードTexCoordのインデックスを変えることで設定したインデックスのUVを使用することができる