OmniAICreator/Qiita-1.07M huggingface dataset:
（Conoha for Games）7 Days to Die のサーバテンプレートが最新でない場合にアップデートする方法

## 記事を公開しようとしたきっかけ
⒈ テンプレートを扱っているVPSサービスは複数ゲームを扱うため、公式が更新あった際に瞬時に対応するのが難しい。
⒉ X（旧Twitter）で困っている人が多かった。
⒊ Ubuntuの最低の知識なくやってうまくいかない人が多い。

## 前提
サーバーファイル格納場所　`/opt/7dtd/7dtd_server/`
サーバーのディレクトリに移動 `cd /opt/7dtd/7dtd_server/`

## 目次
⒈ コントロールパネルのコンソールかSSHクライアントソフトで接続
⒉ 7 Days to Dieのサービスを停止
⒊ 現状のサーバ設定ファイル（serverconfig.xml）のバックアップ
⒋ アップデートツールの steamcmd ダウンロード
⒌ steamcmd を使用してアップデート
⒍ serverconfig.xml を編集
⒎ 7 Days to Dieのサービスを起動
おまけ：MODを入れて遊ぶ

二回目以降は1-2-3-5-6-7

## 7 Days to Die のアップデート方法
### ⒈ コントロールパネルのコンソールかSSHクライアントソフトで接続
<details><summary>コンソールの場合</summary>
サーバーの起動や再起動などのボタンがあるところのコンソール<br>
○○ login： `root`
Password：契約時に決めたパスワード（入力しても透明ですが入力してEnter）<br>
</details>

<details><summary>SSHクライアントソフトの場合</summary>
様々なソフトがあるが【 Tera Term 】が主流で使いやすいです。<br>
※セキュリティグループにIPv4v6-SSH追加<br>
<br>
ソフトを立ち上げて最初の画面の情報<br>
ホスト：IPアドレス<br>
サービス：SSH<br>
TCPポート：22<br>
SSHバージョン：SSH2<br>
IPバージョン：AUTO<br>
<br>
OKを押して次の画面の<br>
ユーザ名：root<br>
パスフレーズ：契約時に決めたパスワード<br>

</details>

### ⒉ 7 Days to Dieのサービスを停止
```
systemctl stop 7dtd
```

### ⒊ 現状のサーバ設定ファイル（serverconfig.xml）のバックアップ
```
cp /opt/7dtd/7dtd_server/serverconfig.xml /opt/7dtd/serverconfig.xml.bk
```

### ⒋ アップデートツールの steamcmd ダウンロード
下記を順番に
```
cd
wget http://media.steampowered.com/client/steamcmd_linux.tar.gz
tar zxvf steamcmd_linux.tar.gz
chmod +x steamcmd.sh
```

### ⒌ steamcmd を使用してアップデート
下記を順番に
```
./steamcmd.sh
force_install_dir /opt/7dtd/7dtd_server
login anonymous
app_update 294420 -beta latest_experimental - Unstable build
quit
```
補足：`app_update 294420 validate`　安定版（今回ならv1.0 - Version 1.0 Stable）
　　　※b333からデータ増えてないので一個下ので大丈夫かもです。（2024/07/26時点）
　　　`app_update 294420 -beta latest_experimental - Unstable build`　ベータの最新版
　　　`app_update 294420 -beta alpha21.2 validate　- alpha21.2` の数字を変更すれば旧バージョンに下げれるので大型MOD用のサーバを立てれます！


### ⒍ serverconfig.xml を編集
```
cd 
cd /opt/7dtd/7dtd_server/ 
vi serverconfig.xml
```
vi で開いた後 `A` キーを押し左下が `INSERT` となったら中を編集
編集完了したら `ESC` キーを押す
```
:wq
```
を押して保存する。

編集で分からない時は `7dtd serverconfig.xml` 等で調べて探してください。

### ⒎ 7 Days to Dieのサービスを起動
```
systemctl start 7dtd
```

これで最新版や⒌で指定したVersionで起動することができます。

## おまけ：MODを入れて遊ぶ
PCと同じように `Mods`フォルダを作って入れて起動すればいいがコマンドでは大掛かりになるので

⒈ 直接ファイルやフォルダごとを運べる万能ソフト `WinSCP` を入れる。

⒉ 転送プロトコル：`SFTP`
　 ホスト名：`IPアドレス`
  　 ユーザー名：`root`
   　 パスワード：`契約時に決めたパスワード`

⒊ 真ん中のパスが初期が下記のようになってるかと思うので
```
/root/
```
そこを下記に変更
```
/opt/7dtd/7dtd_server/
```
Windowsと同じようにフォルダいじれるのでその場所に `Mods` フォルダを作成 or Windowsで作ったのをドラッグアンドドロップで運ぶ
イメージ下記
```
/opt/7dtd/7dtd_server/Mods
```

追加した際は
```
systemctl stop 7dtd
systemctl start 7dtd
```
これで再起動すれば反映されます。


:::note info
最後まで見ていただきありがとうございます。
わからないことがあれば Discord：ally_nb まで
:::
robloxでassistant その143

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

# 練習問題
pluginで、コイン収集システムを生成せよ。

# サンプルコード

```


local PluginBar = plugin:CreateToolbar("creator0")
local Button1 = PluginBar:CreateButton("creator0", "Create new script", "rbxassetid://4458901886", "Create")

Button1.Click:Connect(function()
	if game:GetService("ServerScriptService"):FindFirstChild("ohiscript") then
		game.ServerScriptService.ohiscript:Destroy();
	end
	local helloScript = Instance.new("Script")
	helloScript.Name = "ohiscript"
	helloScript.Parent = game.ServerScriptService
	helloScript.Source = [[
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData0")

local function saveData(key, val)
	local success, errorMessage = pcall(function()
		playerData:SetAsync(key, val)
	end)
	if success then
		print("Data saved successfully!")
	else
		warn("Cannot save data for player!")
	end
end

local function loadData(key)
	local val
	local success, errorMessage = pcall(function()
		val = playerData:GetAsync(key)
	end)
	return val
end

game.Players.PlayerAdded:Connect(function(player)
	print("入った")
	local v = loadData(player.UserId .. "-coin")
	if v == nil then
		v = 0
	end
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	local coin = Instance.new("IntValue", leaderstats)
	coin.Name = "coin"
	coin.Value = v
end)

game.Players.PlayerRemoving:Connect(function(player)
	print("出た")
	local v = player.leaderstats.coin.Value
	saveData(player.UserId .. "-coin", v)
end)

local Players = game:GetService("Players")

local bomb = Instance.new("Part", workspace)
bomb.Name = "bomb"
bomb.Anchored = false
bomb.Shape = Enum.PartType.Cylinder
bomb.BrickColor = BrickColor.Red()
bomb.Size = Vector3.new(0.5, 3, 3)
local explosionSound = Instance.new("Sound")
explosionSound.SoundId = "rbxassetid://5137964328"
explosionSound.Parent = bomb
local function explode()
	local explosion = Instance.new("Explosion")
	explosion.BlastRadius = 10
	explosion.BlastPressure = 500000
	explosion.Position = bomb.Position
	explosion.Parent = game.Workspace
	explosionSound:Play()
end
bomb.Touched:Connect(function(hit)
	local character = hit.Parent
	local humanoid = character:FindFirstChildWhichIsA("Humanoid")
	if humanoid then
		local player = Players:GetPlayerFromCharacter(character)
		bomb:Destroy()
		player.leaderstats.coin.Value = 0
		explode()
	end
end)
local x = math.random(-20, 20)
local z = math.random(-20, 20)
bomb.Position = Vector3.new(x, 8, z)
while true do
	local part = Instance.new("Part", workspace)
	part.Name = "Coin"
	part.Anchored = false
	part.Shape = Enum.PartType.Cylinder
	part.BrickColor = BrickColor.Yellow()
	part.Size = Vector3.new(0.5, 3, 3)
	part.Touched:Connect(function(hit)
		local character = hit.Parent
		local humanoid = character:FindFirstChildWhichIsA("Humanoid")
		if humanoid then
			local player = Players:GetPlayerFromCharacter(character)
			part:Destroy()
			player.leaderstats.coin.Value += 1
		end
	end)
	local x = math.random(-30, 30)
	local z = math.random(-30, 30)
	part.Position = Vector3.new(x, 8, z)
	wait(2)
end
	]]
	print("ok")
end)


```

以上。
Azure OpenAI Dev Day参加レポート

# はじめに
Azure OpenAI Service Dev Dayに参加してきました。

**イベント日：2024/7/25（木）**

**場所：東京都 大手町プレイス**

**公式サイト** 
https://aoai-devday.com/

Azure OpenAI Serviceを活用する複数のコミュニティの祭典として開催されています。
自社内のプロダクトでもAzure OpenAIを利用したプロダクトを開発しているため、情報収集を目的に参加しました。


# イベント報告

午後からは２つの場所に分かれましたので、すべてのセッションが聞けたわけではありませんが、
参加したセッションで印象に残った内容をピックアップします。

#### オープニングセッション
今回の会の中心人物である吉田真吾さん、三宅和之さん、榎並利晃さんの３名によるオーニングセッション。
まだ世の中が模索をしている最中なので、みんなでシェアしながら取り組んでいこうとのこと。その通りだと思いました。

* コミュニティ立ち上げの経緯
![メディア.jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/593c0445-a13e-141e-a6bb-83f57c06a46f.jpeg)


* コミュニティの運営者を募集中とのこと
![メディア (2).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/85273f63-6b08-5c5f-bf5c-a6bb8a359f24.jpeg)


#### 伝統と革新の境界で挑む生成AI導入の経験知（トヨタコネクティッド　AI統括部 西山さん）

トヨタコネクティッドのAI統括部で自社内に生成AI導入などを推進している西山さんのセッションです。
自社内向けの生成AI（企業ChatGPT）を進めている立場として、非常に参考になりました。
開発チーム側がやりたいことを優先しがちですが、利用者の意見を聞きながら育てていく意識が大事だと感じました。

またnoteでも取り組み情報を公開しているとのことでした。
https://note.com/toyotaconnected/m/m02f9fc1eb526

![メディア (5).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/65fb3150-bf96-e6c5-d00e-90acfef44da3.jpeg)
![メディア (6).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/c955129a-5982-50d3-d086-1aaa6d1f2ab6.jpeg)
![メディア (7).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/7e63f29e-309f-bcdd-0f93-09bc664e3617.jpeg)


#### RAGのサービスをリリースして1年が経ちました（株式会社 アイアクト　江頭さん）

Azure OpenAI×Watsonでサイト内検索サイトのサービスを提供しているアイアクトさん。
ChatGPTが有名すぎて、生成AI＝チャットUIのイメージが付いてしまっていますが、確かに情報検索という用途においては検索UIが良いと思いました。


![メディア (8).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/b44a4b3f-3521-734d-a997-991011d38634.jpeg)
![メディア (9).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/8a62df12-538d-e2c5-04e4-bdf532234063.jpeg)


#### LLMアプリ開発におけるTipsやAOAIの活用ポイント（日本マイクロソフト 蒲生さん）　
AOAI活用におけるポイントが参考になりました。しっかりとAOAIの特徴をつかんで取り組まないと、精度があがらない⇒利用者の評価も低下になると感じました。
LLMシステム開発大全を公開してくださっているので、一読したいです。
https://speakerdeck.com/hirosatogamo/chatgpt-azure-openai-da-quan

![メディア (10).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/23eaf706-f3d0-24ec-800b-bac426e3ba11.jpeg)

![メディア (12).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/bdeded5e-df0c-bcda-edbe-70381b6fbe56.jpeg)


# 懇親会
* ウルトラクイズは３２番でTシャツはもらえず
* LT会
    * ベネッセさんは週に2,000人（5,000人だったかも・・）の社内向けChatGPTの利用者がいる（スゴイ）
* ドーナッツは美味しかった

# さいごに
今回のイベントに参加できて良かったです。
理解が曖昧なままになっているAzure AI SearchとRAGの実装に向けて、取り組みたいと感じました。
また機会があれば、是非イベントに参加したいです。

帰りに食べたラーメン
![メディア (13).jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100890/e80dd5db-7200-83f3-36f9-9752629ae614.jpeg)
生成AIのTokenという単位について

## はじめに
OpenAIのAPIに触れるなかでTokenという単語がでてくることがあります。そのTokenについて知らなかったので調べてみました。

## Tokenとは
一言でいうとテキストの最小単位です。文章を処理する際、単語や句読点、数字などの要素に分割するプロセスを「トークナイゼーション」と呼び、分割された要素1つ1つがTokenです。TokenはLLM等言語処理でも使用されます。

## トークナイゼーションの例

**例1**
9つに分けられるので9トークンと数えることができます。


![スクリーンショット 2024-07-24 14.52.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1201315/e4828361-0fa7-0a7e-8ffc-3f3934f8c602.png)

**例2**
日本語だと区切られる単位が多いためトークン数が増えます。
下記文章で13トークンです。

![スクリーンショット 2024-07-24 14.58.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1201315/e1e6e206-2abe-d006-d619-92fdb7a6dec1.png)

**例3**
下記コードだと35トークンです。
![スクリーンショット 2024-07-26 8.19.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1201315/d1a15e61-23b3-40b8-9fae-37fcb26c69d0.png)

tokneizerを使用してカウントしました。

https://platform.openai.com/tokenizer

## ChatGPT4oのトークンの料金について調べる
ChatGPTなどのAPIを使用する場合、使用するトークン数に基づいて料金が発生します。送信された入力トークンの数と、API によって返された出力内のトークンの数に基づいて計算されます。

使用方法にもよりますがChatGPT4oの場合は 5.00ドル/100万入力トークンとなるようです。

https://openai.com/api/pricing/

## 最後に
Tokenが何者か知らずOpenAIのAPIを使用していましが正体を知ることができました。
初歩的な知識ですが理解できよかったです。

## 最後に
私の働いている会社で経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談から応募してみてください！

https://jambo-support.com/recruit_engineer/
macのターミナルでシェルスクリプトを実行できない

## 問題
エラー内容
```sh
$ ./test.sh 
-bash: ./test.sh: Operation not permitted
```

## 解決方法
システム設定から「ターミナル」にフルディスクアクセスを許可することで実行できるようになります。
「システム設定」->「プライバシーとセキュリティ」->「フルディスクアクセス」->「＋」ボタン押下 -> ターミナルを追加

上の手順でも状況が変わらない場合、以下について確認してみてください。
Macでは、ダウンロードしてきたファイルは実行できないそうです。

https://discussions.apple.com/thread/253681758?sortBy=best

この対応として、以下のコマンドを実行するか、ローカルで別ファイルを作成し、ダウンロードしたファイルの中身をコピペして、その新しくローカルで作成したファイルを実行してください。
```sh
xattr -d com.apple.quarantine ./test.sh
```

## 参考
https://qiita.com/KEINOS/items/0366f1c281b574a79cfb

https://discussions.apple.com/thread/253681758?sortBy=best
yukicoder No.36 素数が嫌い！　解説

[問題文](https://yukicoder.me/problems/no/36)
# 解説
今回は、与えられた数が素数かどうかの判定ではない。**合成数を約数に持つか**の判定だ。謎のWAを出している人はまずここを読み間違えていないか確認しておこう。
そのうえで、解説を書く。
まず、素数判定については以下の方法でできる。
**ある数$N$が素数かどうかの判定は、$\sqrt{N}$までで割り切れるかどうかの判定でできる**。
では、合成数の約数を持つかの判定はどうするか。
例えば、ある数$i$が$N$に割り切れたとする。
$i$が合成数かどうかの判定も$\sqrt{i}$までで割り切れるかどうかの判定をする。
もし割り切れた数があったなら、$i$は合成数なので$N$は条件を満たす数になる。
# C++での解答例
```C++
#include <bits/stdc++.h>
using namespace std;
using ll=long long;

int main(){
  ll n;cin>>n;
  for(ll i=2;i*i<=n;i++){
    if(n%i!=0)continue;
    bool ok=false;
    for(ll j=2;j*j<=i;j++)
      if(i%j==0){
        ok=true;
        break;
      }
    for(ll j=2;j*j<=n/i;j++)
      if((n/i)%j==0){
        ok=true;
        break;
      }
    if(ok){
      cout<<"YES\n";
      return 0;
    }
  }
  cout<<"NO\n";
}
```
【HTTP】初心者必見！ゼロから学べる実践入門

HTTPとは？
---
HTTPは、クライアント（通常はウェブブラウザ）とサーバー間でデータを交換するためのプロトコルです。
HTTPはステートレスであり、各リクエストは独立して処理されます。

バージョン
---
`HTTP/1.0`: 初期のバージョンで、単一の接続で単一のリクエストとレスポンスを処理。
`HTTP/1.1`: 接続の持続（Keep-Alive）をサポートし、複数のリクエストを同じ接続で処理可能。
`HTTP/2`: マルチプレキシング、ヘッダ圧縮、優先順位付けなどにより効率化。
`HTTP/3`: QUICプロトコルに基づき、さらに高速化と安定性を追求。

HTTPメソッド
---
`GET`: データの取得。
`POST`: データの送信。
`PUT`: データの更新。
`DELETE`: データの削除。
`PATCH`: データの部分更新。
`HEAD`: ヘッダーのみの取得。
`OPTIONS`: サーバーの機能情報の取得。

HTTPステータスコード
---
- 2xx: 成功
200 OK: 正常にリクエストが成功。
201 Created: リソースが作成された。

- 3xx: リダイレクト
301 Moved Permanently: 永続的にリソースが移動。
302 Found: 一時的にリソースが移動。

- 4xx: クライアントエラー
400 Bad Request: 無効なリクエスト。
401 Unauthorized: 認証が必要。
404 Not Found: リソースが見つからない。

- 5xx: サーバーエラー
500 Internal Server Error: サーバー内部エラー。
503 Service Unavailable: サービスが利用不可。

HTTPヘッダー
---
リクエストやレスポンスに関する追加情報を提供します。

`Content-Type`: データのメディアタイプ。
`Authorization`: 認証情報。
`Cache-Control`: キャッシュポリシー。
`User-Agent`: クライアント情報。

まとめ
---
HTTPはウェブ開発において欠かせないプロトコルです。基本を理解し、ベストプラクティスを実践することで、安全で効率的なウェブアプリケーションを構築できます。
【Laravel】Illuminateにある主要メソッド Pagination編

### 言語
- Laravel8

## Illuminateとは
- Laravelが提供する様々なサービスやコンポーネントを構成するための基盤を提供している。
- サービスやコンポーネントは``Illuminate``名前空間内に整理されている

### どこにあるか？
**``プロジェクトディレクトリ\vendor\laravel\Framework\src\Illuminate\~``**

## Illuminate\Pagination
- Laravelのページネーション機能を提供するためのクラスがある。

### ``paginate()``
- 指定された項目数で結果をページ分割
    ```Laravel
     $users = DB::paginate(10);
     ```

### ``simplePaginate()``
- シンプルな「前へ」「次へ」リンクだけを含む簡易的なページネーション
    ```Laravel
     $users = DB::simplePaginate(10);
     ```

### ``links()``
- ページネーションのリンクを生成
    ```Laravel
     {{ $users->links() }}
     ```

### ``url()``
- 指定されたページ番号のURLを取得
    ```Laravel
     $url = $users->url(5);
     ```

### ``appends($key, $value = null)``
- ページネーションリンクに追加のクエリ文字列パラメータを追加
    ```Laravel
     $users = DB::->paginate(10)->appends(['sort' => 'name']);
     ```

### ``currentPage()``
- 現在のページ番号を取得
    ```Laravel
     $currentPage = $users->currentPage();
     ```

### ``hasPages()``
- ページネーションが複数ページに分かれているかどうか確認
    ```Laravel
     if ($users->hasPages()) {
     
     }
     ```

### ``hasMorePages()``
- 次のページが存在するかどうか確認
    ```Laravel
     if ($users->hasMorePages()) {

     }
     ```

### ``count()``
- 現在のページのアイテム数を取得
    ```Laravel
     $count = $users->count();
     ```

### ``total()``
- ページネーションの総アイテム数を取得
    ```Laravel
     $total = $users->total();
     ```

### ``lastPage()``
- 最後のページ番号を取得
    ```Laravel
     $lastPage = $users->lastPage();
     ```

## 使用例

```Laravel:Controller
    use App\Models\User;

    class UserController extends Controller
    {
        public function index()
        {
            $users = User::paginate(10); //10件ごと取得

            return view('index', compact('users'));
        }
    }
 ```

```blade:blade
    <body>
        <h1>Users</h1>
        <ul>
            @foreach ($users as $user)
                <li>{{ $user->name }}</li>
            @endforeach
        </ul>
    
        {{ $users->links() }}
    </body>
 ```

## 私のIlluminate関連記事

https://qiita.com/Jisu/items/47361c5c1a80ad71655c

https://qiita.com/Jisu/items/c92501a4595da0e6e2c3

https://qiita.com/Jisu/items/a3eb5dbb60e77431afa9

https://qiita.com/Jisu/items/2e642698c3ce9b141c2f

https://qiita.com/Jisu/items/da70992ec3196d0ed8cb
非同期処理とは【初心者向け】

非同期処理とは？
---
非同期処理とは、あるタスクを実行しつつ、他のタスクを並行して処理することです。
これにより、処理の待ち時間を最小限に抑え、効率的なプログラムを作成することができます。

コールバック関数
---
最も基本的な非同期処理の方法はコールバック関数を使用することです。
```js
function fetchData(callback: (data: string) => void) {
    setTimeout(() => {
        callback("データ取得完了");
    }, 1000);
}

fetchData((data) => {
    console.log(data);
});
```

Promise
---
コールバック関数の欠点（コールバック地獄）を解消するために、Promiseが導入されました。Promiseは、非同期操作の完了や失敗を扱うオブジェクトです。
```js
function fetchData(): Promise<string> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("データ取得完了");
        }, 1000);
    });
}

fetchData().then((data) => {
    console.log(data);
});
```

async/await
---
Promiseの構文をさらにシンプルにするために、async/awaitが登場しました。
これにより、非同期処理を同期処理のように書くことができます。
```js
async function fetchData(): Promise<string> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("データ取得完了");
        }, 1000);
    });
}

async function main() {
    const data = await fetchData();
    console.log(data);
}

main();
```

エラーハンドリング
---
Promiseでは.catchメソッドを使用し、async/awaitではtry...catchブロックを使用します。
```js
function fetchData(): Promise<string> {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error("データ取得失敗"));
        }, 1000);
    });
}

fetchData().then((data) => {
    console.log(data);
}).catch((error) => {
    console.error(error);
});
```

async/awaitでのエラーハンドリング
```js
async function fetchData(): Promise<string> {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error("データ取得失敗"));
        }, 1000);
    });
}

async function main() {
    try {
        const data = await fetchData();
        console.log(data);
    } catch (error) {
        console.error(error);
    }
}

main();
```

実践的な例
---
非同期処理の実践的な例として、APIからデータを取得するシナリオを考えます。
ここでは、Fetch APIを使用します。
```js
async function fetchUserData(userId: number): Promise<any> {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
    if (!response.ok) {
        throw new Error('データ取得失敗');
    }
    return response.json();
}

async function main() {
    try {
        const userData = await fetchUserData(1);
        console.log(userData);
    } catch (error) {
        console.error(error);
    }
}

main();
```

まとめ
---
非同期処理は、基本的なコールバック関数から始まり、Promiseやasync/awaitを使用することで、より読みやすく、保守しやすいコードを書くことができます。
Javaで「コマンドライン引数の数を確認」の動作を確認してみた

# 概要

Javaで「コマンドライン引数の数を確認」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/main/index2.html

# 実装

以下のファイルを作成しました。
```JSample2_1.java
class JSample2_1{
  public static void main(String args[]){
    if (args.length != 2){
      System.out.println("引数を2つ指定して下さい");
      System.out.println("JSample2_1 値1 値2");
      System.exit(1);
    }

    System.out.println("「" + args[0] + "」");
    System.out.println("「" + args[1] + "」");
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample2_1.java 
$ java JSample2_1 値1 値2
「値1」
「値2」
```

# まとめ

何かの役に立てばと。
ASP.NET Core(Docker版)でhttpsを使用しない設定

- Program.csの``app.UseHttpsRedirection();``を削除する
```Program.cs
...
//app.UseHttpsRedirection();
...
```
- launchSettings.jsonの``ASPNETCORE_HTTPS_PORTS``を削除、``useSSL: true``をfalseにする
```launchSettings.json
...
"environmentVariables": {
  ASPNETCORE_HTTPS_PORTS": "8081", //ここを削除
  "ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true, 
"useSSL": true, //ここをfalseに変更
...
```
- docker-compose.override.ymlがある場合は、今設定したものを上書きする内容が書かれていないか確認する
```docker-compose.override.yml
services:
  d-data-server:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8080
      # - ASPNETCORE_HTTPS_PORTS=8081 <-これとか
    ports:
      - "8080"
      # - "8081" <-これとか
```

以上です。
VisualStudioでDockerComposeの変更が適応されないときは多分overrideされてる

# 結論
docker-compose.ymlを上書きするdocker-compose.override.ymlも一緒に作成されているので、docker-compose.ymlを編集する際はそちらも併せて修正する必要があることがあります。

# 経緯
複数のDockerプロジェクトを持つASP.NET coreのソリューションにて、VisualStudio2022にコンテナオーケストレーションを作成してもらってました。
プロキシサーバーを通してリクエストが来る予定なので、httpsの設定を除去しようとして各種設定を弄っていたところ、まったく適用してくれなくて困りました。
よく見たらVisualStudioが自動で作成してくれたdocker-compose.override.ymlで設定が上書きされていたせいで適用されていませんでした。おしまい。
rubyで(変な解き方で) FizzBuzzを解いてみる

みなさん、こんにちは！

筆者はRuby on RailsでRails7の初期 + ruby 3.2 環境ぐらいまでは書いていましたが、ここ半年は専ら[Misskey](https://github.com/misskey-dev/misskey)の開発などに勤しんでいるのもあり、TypeScriptばかりを書く日々を送っていました。

そんなある日、ふとQiitaを開いてみると[paiza×Qiita記事投稿キャンペーン「プログラミング問題をやってみて書いたコードを投稿しよう！」](https://qiita.com/official-events/9ab96aa95d62fe3cbdd7)なんてキャンペーンをやってたので、久々にrubyでも書こうと思い、記事を書くことにしました。

## 対象の問題
久々にrubyでも書くので手堅くみんな大好きFizzBuzz問題でも解いてみようと思います。

[Fizz Buzz (paizaランク C 相当)](https://paiza.jp/works/mondai/c_rank_skillcheck_sample/fizz-buzz)

プログラミング問題としては定番なのでご存じの方も多いでしょうが、簡単に問題を説明すると、

- 1~100までの数字Nが与えられる
- 各数字ごとに、1からNまでの数字のうち次を出力する
    - 3の倍数ならば "Fizz"
    - 5の倍数ならば "Buzz"
    - 3の倍数かつ5の倍数ならば "Fizz Buzz"
    - いずれにも当てはまらなければ 数字N

 といった問題です。

 この後模範解答を紹介しますが、そんなの簡単だろという方はぜひ[実際に書いたコード](#実際に書いたコード)までジャンプしましょう。

 ## おそらく想定される一般的な解き方
 模範解答は大事です。プログラミングの繰り返しと条件分岐が学べる基本問題ですね。
 ```ruby
 # まずは数字を取得
 N = gets.to_i
 # 1~N まで 繰り返しで順番に条件をチェックし条件に応じて出力
 (1..N).each do |i|
  if i % 3 == 0 && i % 5 == 0
    puts "Fizz Buzz"
  elsif i % 3 == 0
    puts "Fizz"
  elsif i % 5 == 0
    puts "Buzz"
  else
    puts i
  end
 end
 ```

## 実際に書いたコード
FizzBuzzの解き方という初歩的な課題で、ありふれた模範解答を載せてもインターネット上に大量の例が載っているので面白くないと思います。特に記事投稿用ということで目の肥えたQiita読者の方も楽しんでいただけたらいいなと思います。

### コンセプト
- コードを圧縮可能
- rubyのEnumerableの良さを生かす
- ちょっと捻ったコード

### 実物
```ruby
outs = { 15 => 'Fizz Buzz', 5 => 'Buzz', 3 => 'Fizz' }
(1..gets.to_i).each { |i| puts i if (outs.none? { |k,v| (puts v;true) if i % k.to_i == 0 }) }
```

たった2行です。
ここまで圧縮されていると解説もしにくいので少し読みやすくして見ましょう。
(rubyでは一般的には可読性のためにeachやifは`do ~ end`で書かれますがこのように書くことも可能です。)

### 解説
```ruby
outs = { 15 => 'Fizz Buzz', 5 => 'Buzz', 3 => 'Fizz' }

(1..gets.to_i).each do |i|
  if outs.none? { { |k,v| (puts v;true) if i % k.to_i == 0 } }
    puts i
  end
end
```

まずは`outs`を宣言しています。これはそれぞれの倍数に対して出力する文字列をHashとして持たせています。rubyは文字列、Symbol、数字など色々とHashのキーとして扱えます。

冒頭に`15`という数字を直で書いてあります。
一見わかりにくいかもしれませんが、これは3の倍数かつ5の倍数である数字が最小公倍数である15の倍数であるという性質を利用しています。

また、rubyでのHashは1.9以降、順番を保持されるようになっています。（2009年に1.9がリリースされたみたいなので執筆時点でももう15年が経ってます。すごい）

次に、模範解答と同じようにループ処理をしています。
ループ処理の中のif文の条件に注目してください。
RubyのHashはEnumerableのメソッドが使えます。その中に`none?`というメソッドがあるのですが、これが非常に重要な役割を果たしています。

> ブロックを指定した場合は、Enumerable オブジェクトのすべての要素をブロックで評価した結果が、すべて偽であれば真を返します。そうでなければ偽を返します。

https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/none=3f.html

ブロック内で`15, 5, 3`についてそれぞれ割り切れるかどうかを確認し、割り切れる場合は対応する文字列を出力しtrueを返し、そうでない場合は何も返しません。Hashの順序は保証されているので実行順は問題ないです。

何も返らない場合、rubyでは偽と評価されるため、もし割り切れる数字がない場合には`none?`で評価した値が偽（`false`）, 割り切れる値がある場合には真（`true`）となります。

そのため、割り切れる数字がない場合はif文の中身の処理が走り、もともとの文字列を出力することになります。


## さいごに
やはりこういった基礎の問題は普通に解くのも楽しいですが、言語固有の便利なメソッドや特性を利用して工夫して解くのもまた楽しさがあります。


皆さんもたまには利用する言語のドキュメントなどを眺めていると、こういった便利メソッドなどに出会えるかもしれません。Rubyは日本生まれなこともあり公式ドキュメントが日本語で非常に読みやすいですね。


それでは、よいコーディングライフを。
Memcached のインストール

# はじめに

メモがてら記録します。

# 前提

- Ubuntu 24.04 LTS (Noble Numbat)
- Memcached 1.6.29

# 手順
1. インストールに必要なツールをインストールする
    ```bash
    sudo apt install gcc make libevent-dev
    ```

2. パッケージをダウンロードする (https://memcached.org/downloads)
    ```bash
    curl -LkvOf https://memcached.org/files/memcached-1.6.29.tar.gz
    ```

3. パッケージを展開し、展開されたディレクトリの中に移動する
    ```bash
    tar xzf memcached-1.6.29.tar.gz
    cd memcached-1.6.29
    ```

4. configure スクリプトを実行する
    ```bash
    ./configure
    ```

5. 次のコマンドを実行する
    ```bash
    make
    make test
    sudo make install
    ```

# 参考
- [From source](https://github.com/memcached/memcached/wiki/Install#from-source)
- [Downloads](https://memcached.org/downloads)
「レビューイ」「レビュアー（レビューア）」が覚えられない人へ

私のように、英単語がアルファベットの不規則な羅列に見えてカタカナ言葉が中々覚えられない方へ

英単語の<font color="DarkOrange">接尾辞</font>の意味が分かると覚えやすくなるかもしれません

# レビュアー（レビューア）（英：reviewer）
「動詞」＋「er(接尾辞)」＝ <font color="DarkOrange">～する人</font>
「review」＋「<font color="DarkOrange">er</font>(接尾辞)」 ＝ レビュー <font color="DarkOrange">する人</font>
# レビューイ（英：reviewee）
「-ee(接尾辞)」 ＝ <font color="DarkOrange">〜される人</font>
「review」＋「<font color="DarkOrange">ee</font>(接尾辞)」 ＝ レビュー <font color="DarkOrange">される人</font>

# ポイント？
> 「動詞」＋「er(接尾辞)」＝ ～する人

 は、身近で使われている
「play<font color="DarkOrange">する人</font>」→play<font color="DarkOrange">er</font>
と関連付けると覚えやすいかもしれないです。

以下も同様。
|employ<font color="DarkOrange">er</font>  |employ<font color="DarkOrange">ee</font>  |
|---|---|
|雇用主<br>雇用<font color="DarkOrange">する人</font>  |従業員<br>雇用<font color="DarkOrange">される人</font>  |



# 参考サイト
https://wa3.i-3-i.info/word1517.html

https://wa3.i-3-i.info/word12684.html

http://www.etn.co.jp/etymology/ee/

https://www.shinyujump.net/study/%E8%8B%B1%E8%AA%9E%E3%81%AB%E3%80%8Cer%E3%80%8D%E6%8E%A5%E5%B0%BE%E8%BE%9E%E3%82%92%E3%81%A4%E3%81%91%E3%82%8B%E3%81%A8%E4%BD%95%E3%81%8B%E3%82%92%E3%81%99%E3%82%8B%E4%BA%BA%E3%81%AB%E3%81%AA/
投稿 25 基礎理論 2024/07/25

本日の勉強時間　4H

n進数の基数重みの公式
基数n
整数部分の重み　：０乗　1乗　2乗
少数部分の重み　；−１乗　-2乗![IMG_6488.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579814/108f67ad-307c-8af2-c56c-9a6bdb2ba666.jpeg)
Markdown記法について

# 目的
Markdown記法のチートシートはあちらこちらに存在するが、あえてそれを自ら表現することにより理解を深め、及び身につけること並びに自らの表現が他者の理解に資する可能性があることを鑑み、情報を共有することを目的とする。
# Markdown記法
## 見出し
- 文頭に、\# 文　のように書くと、見出しになる。
- \#の後に半角スペースを入れること。
- \#の前に半角スペースを入れても構わない。
- #の数によってレベルを表す。
\## レベル２の見出し
\### レベル３の見出し
## 強調
- \*文\*　のように文を囲むと、文がイタリック体で表示される。HTMLでいうところのemタグ。\_でもよい。
ここを→*イタリック体*にする。
- \*\*文\*\*　のように文を囲むと、文が太字になる。HTMLで言うところのstrongタグ。\__でもよい。
ここを→**太字**にする。
## 打ち消し線
- \~~文\~~　のように文を囲むと、文に打ち消し線を引くことができる。
ここを→~~打ち消す~~。
## 順序なしリスト
- 文頭に、\- 文、\* 文、\+ 文　のように書くと、順序なしリストになる。
- 記号の後には半角スペースを入れること。
- 記号の前にタブ文字を入れると、レベルが一つ下がる。
## 順序ありリスト
- 文頭に、数字\.　のように書くと、順序ありリストになる。
- \.の後には半角スペースを入れること。
- 数字はなんでも良い。
- 記号の前にタブ文字を入れると、レベルがひとつ下がる。この場合に、レベルの下がったリストは数字の1から始めなければ順序ありリストにならない。
## 引用
- 文頭に、\>を置く。
- 複数行に渡る場合は、各行に>を置くこと。
- 引用の前後には空行を置くこと。
- \>の数を増やすと、その行以降がネストした引用となる。
## 水平線
- \---又は\***のように書くと、水平線となる。
## リンク
- \[表示テキスト\]\(URL "タイトル"\)　のように書くと、リンクとなる。
- \"タイトル\"は省略できる。
## 画像埋め込み
- リンクの書き方の前に\!を置く。
## コードブロック
- \```　を置いた行で囲んだところはコードブロックとなる。
- 始めの\```において、\```言語名:ファイル名　のように書くと、シンタックスハイライトが適用される。
```python:例
print()
```
- 言語名の前に、diff_　を置くと、Diffを追加できる。行の先頭に`-`、`+`を置くことでDiffを表現できる。
```diff_python:例
- print("Hello, Warld!")
+ print("Hello, World!")
```

## コードスパン
- \`コード\`のように書くと、コードをインライン表示することができる。
- コードスパン内でn連続の\`を使いたいときは、コードスパンの開始及び終了の\`の数をn+1個に増やす。
# 参考文献
[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
Squid のインストール

# はじめに
今更感ありますが、メモがてら記録します。

# 前提
- Ubuntu 24.04 LTS (Noble Numbat)
- Squid 6.10

# 手順
1. インストールに必要なツールをインストールする
    ```bash
    sudo apt install gcc g++ make libcppunit-dev
    ```

2. パッケージをダウンロードする (https://www.squid-cache.org/Versions/v6/)
    ```bash
    curl -LkvOf https://www.squid-cache.org/Versions/v6/squid-6.10.tar.gz
    ```

3. パッケージを展開し、展開されたディレクトリの中に移動する
    ```bash
    tar xzf squid-6.10.tar.gz
    cd squid-6.10
    ```

4. configure スクリプトを実行する
    ```bash
    ./configure \
    --prefix=/usr \
    --localstatedir=/var \
    --libexecdir=${prefix}/lib/squid \
    --datadir=${prefix}/share/squid \
    --sysconfdir=/etc/squid \
    --with-default-user=proxy \
    --with-logdir=/var/log/squid \
    --with-pidfile=/var/run/squid.pid
    ```

5. 次のコマンドを実行する
    ```bash
    make
    make check
    sudo make install
    ```

# 参考
- [How do I compile Squid?](https://wiki.squid-cache.org/SquidFaq/CompilingSquid#how-do-i-compile-squid)
- [Debian, Ubuntu](https://wiki.squid-cache.org/SquidFaq/CompilingSquid#debian-ubuntu)
【Python】importの相対パスを解決

## はじめに
Python で以下のようなディレクトリ構造のとき， app/hoge.py と test/fuga.py 間で相対パスを使いたい時の備忘録です．

**ディレクトリ構造**

```bash
root
├── app
│   └── hoge.py
└── test
    ├── __init__.py
    └── fuga.py
```

## 結論
以下の手順で，hoge.py から fuga.py のクラスをインポートして使用することができます．

**ソースコード**

```hoge.py
import sys
sys.path.append('../')
from test import Fuga

def main():
    Fuga.greeding()

if __name__ == "__main__":
    main()
```
```__init__.py
from .fuga import *
```
```fuga.py
class Fuga:
    @staticmethod
    def greeding():
        print("Hello from Fuga!")
```

**コマンド**

```bash
$ cd ./app
$ python3 hoge.py 
```

## 事前知識
**相対パス**
相対パスは，カレントディレクトリを`.`，現在の階層から1つ上の階層を`..`で表記することができます．app がカレントディレクトリの場合，fuga.py は `../test/fuga.py` と表せます．

**`__init__.py`**
`__init__.py` をディレクトリ内に作成すると，そのディレクトリがパッケージとして認識されます．

**sys.path.append**
sys.pathは、Pythonがモジュールやパッケージを検索する際に使用するディレクトリのリストです。Pythonはimport文を実行するとき、このリストに含まれるディレクトリを順番に検索し、最初に見つかったモジュールをインポートします。つまり親ディレクトリへのpathはsys.pathにないためエラーになります．(次項参照)


## 注意
Pythonのimport文では，hoge.py から fuga.py を呼び出そうとした時 `from ..test import Fuga` のように表記したくなりますが，`ImportError: attempted relative import with no known parent package` エラーが発生します．
これは，スクリプトを直接実行する場合，Pythonがそのスクリプトの親パッケージを認識しないためです．
Pythonはセキュリティの問題で，認識しないようにしているそう...

この問題を回避するために，`sys.path` を使って親ディレクトリ(ここでいうroot)を追加します．それにより，子ディレクトリ（ここでいう/app）から親を認識できるようにします．

## 詳細説明
**hoge.py**
`sys.path.append('../')` を使って親ディレクトリをパスに追加することで，test パッケージをインポートできるようにします．
rootディレクトリからは`/test, /app`が見えるためインポートできるようになります．
その後，`from test import Fuga` で fuga.py からクラスをインポートします．

:::note warn
※ `from ディレクトリ名 import クラス名`に注意してください．
ファイル名(fuga)とクラス名(Fuga)の間違いで悩んでたことがあります．
:::

**`__init__.py`**
このファイルは，test ディレクトリをパッケージとして認識させるために必要です．
`__init__.py` ファイル内で fuga.py をインポートします．

**fuga.py**
クラス Fuga を定義します．このクラスには，greeding という静的メソッドが含まれており，`"Hello from Fuga!"` と出力します．

## 実行方法
app ディレクトリに移動して hoge.py を実行します．これにより，hoge.py が親ディレクトリ `..` をパスに追加し，test パッケージから Fuga クラスを正しくインポートできるようになります．

```bash
$ cd ./app
$ python3 hoge.py 
```

**実行結果**

```plaintext
Hello from Fuga!
```

## 参考
https://www.ipride.co.jp/blog/2449

https://qiita.com/u943425f/items/bd94a30b52c9296e942d

https://zenn.dev/ama_c/articles/43bd4171a9855d
Azure のワークロードID (マネージド ID とサービスプリンシパル) を整理する

こんにちは、アーキテクトのやまぱんです。
今回は Azure のワークロード ID、具体的にはマネージドID と サービスプリンシパル についてまとめます。
補足コメントや質問、<font color="red">**いいね、拡散**</font>、是非お願いします🥺！
間違ってたら<font color="red">**優しく**</font>教えてください！

## モチベ
以前に参加した 2024/05/31 に開催された コミュニティイベント 「**すきやねんAzure-セキュリティも考えてる？ 動いて終わりじゃないですよ！！」** で説明されたもののまとめです。
**復習するまでが勉強会です(かなり遅くなったけど）**

https://sukiyanenazure.connpass.com/event/316769/

当日のデモで使用されたスクリプトはこちら

https://github.com/hiyoshino/Sukiyanen_ManagedID

+ すきやねんAzure の紹介はこちら

https://qiita.com/aktsmm/items/b957775f197d72274968

## ワークロードID とは
**マネージドID** と **サービスプリンシパル** を合わせて指すことば。サービスプリンシパルはクライアントIDとも呼ばれたり。
ユーザー(人間)が認証する ID ではなく、システムやソフトウェアが使用する ID
ソフトウェア (スクリプト、アプリケーション、サービス、スクリプト、コンテナーなど) に割り当てる ID 

## マネージド ID と サービスプリンシパル の差異

||マネージド ID|サービスプリンシパル|
|:-|:-|:-
|トークンエンドポイント|Azure Instance Metadata Service  <br>http://169.254.169.254/metadata/identity/oauth2/token|https://login.microsoftonline.com/ **[Tenant_ID]** /oauth2/v2.0/token|
|対象リソースの場所|Azure上のリソースの対応サービス(Azure VM、App Service、Functionsなど)|Microsoft Entra IDに接続できればどこでもOK(オンプレのアプリに組み込むことが可能)
|認証方法|証明書|クライアント シークレット文字列または証明書|
|ライフサイクル管理|自動的に管理されるため、クライアントシークレットや証明書のローテーションが不要|クライアントシークレットや証明書のローテーションが必要|

## マネージド ID の方が安全な理由
+ Azure 環境でのみ利用可能なトークンエンドポイントからOauth2.0 アクセストークンを発行（トークンの有効期限は１時間で次回アクセス時にトークンが新たに取得されます)
+ トークン取得時の認証には証明書認証を使用しており安全
+ 証明書は Azure 内部で保持しており、ダウンロードは不可


## ２つのマネージド ID
### システム割り当てマネージド ID
+ Azure リソース（仮想マシン、Functions など）のリソースの一部として作成
+ そのリソースでしか使用できない（他のリソースと共有不可）
+ リソース個別で ID が必要なケースやリソースとともにライフサイクル管理したいケースで利用(リソースを削除すると同時にマネージドIDも削除)

### ユーザー割り当てマネージド ID
+ 個別の Azure リソースとして作成
+ 複数のリソースで共有が可能
+ 明示的に削除が必要
+ 例えば複数の VM で同一のストレージアカウントにアクセスする必要があるケースなどで利用

### トークンの内容をみてみよう
こちら別記事にしました

https://qiita.com/aktsmm/items/5adbf2e1264067ca3d36

## 参考
### マネージド ID を 使って Azure VM から CLI で Azure を操作する。
こちらかこに書いた記事です。

https://qiita.com/aktsmm/items/1a1d8b79f18f0c7a5331

### Azure Instance Metadata Service とは

https://qiita.com/ussvgr/items/f993cf48b29147d30767

### マネージドID をサポートするサービス

https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/managed-identities-status#services-supporting-managed-identities

### Azure AD が発行するトークンの有効期間と考え方 (2023 年版)

https://jpazureid.github.io/blog/azure-active-directory/token-lifetime-2023/

### Microsoft ID プラットフォームのアクセス トークン
https://learn.microsoft.com/ja-jp/entra/identity-platform/access-tokens

> アクセス トークンにより、クライアントは保護された Web API を安全に呼び出すことができます。 Web API は、アクセス トークンを使用して認証と認可を実行します。
OAuth 仕様では、アクセス トークンは、設定された形式を持たない不透明型の文字列です。 ID プロバイダー (IDP) には、GUID を使用するものと、暗号化された BLOB を使用するものがあります。 アクセス トークンの形式は、トークンを受け入れる API の構成によって異なります。
Microsoft ID プラットフォームで開発者によって登録されるカスタム API では、v1.0 および v2.0 と呼ばれる 2 つの異なる形式の JSON Web Token (JWT) のいずれかを選択できます。
tomcat。RHEL8.2。APサーバー内でもcurlコマンドが拒否される。外部から接続不可。どこの設定が悪い？

の問題は、Tomcatサーバーの設定、ネットワーク設定、または他のセキュリティ設定に起因する可能性があります。以下に考えられるいくつかのチェックポイントを示します：

## Tomcatの設定:

Tomcatのserver.xmlファイルを確認し、適切なポートでリスニングしているか確認してください（デフォルトでは8080）。
<Connector>タグの設定を確認し、正しいIPアドレスとポートでリスニングしているか確認してください。
ネットワーク設定:

サーバーのネットワークインターフェース設定を確認し、正しく設定されていることを確認してください。
ifconfigまたはip aコマンドを使用してネットワークインターフェースの状態を確認してください。
## SELinux:

SELinuxは無効にされているとのことですが、念のため確認してください。sestatusコマンドを使用して確認で## きます。
ファイアウォール:

ファイアウォールの設定が無効とのことですが、念のため再確認してください。firewall-cmd --stateコマンドを使用して、ファイアウォールが本当に無効化されているか確認できます。
## Tomcatの起動確認:

Tomcatが正しく起動していることを確認してください。systemctl status tomcatコマンドを使用してTomcatのステータスを確認します。
## ローカルホストからのアクセス:

サーバー上で`curl http://localhost:8080`を実行して、ローカルホストからTomcatにアクセスできるか確認してください。
## 外部からのアクセス:

外部からのアクセスが問題となる場合、サーバーのルーティングやNAT設定に問題がないか確認してください。
また、外部からアクセスする際に、正しいIPアドレスとポートを使用していることを確認してください。
## ログファイルの確認:

Tomcatのログファイル（catalina.outなど）を確認し、エラーや警告メッセージがないか確認してください。
これらのポイントを確認することで、問題の原因を特定し、解決する手助けになるかと思います。どの手順で何かしらの問題が見つかれば、それに対する具体的な対策をさらに検討することができます。
EPUBのパッケージ文書の基本


この記事ではEPUB 3.3 (https://www.w3.org/TR/epub-33/) のパッケージ文書について説明します。

## 基本
EPUB文書は少なくとも１つのパッケージ文書を含んでいる必要があります。複数のパッケージ文書を持っている場合は https://www.w3.org/TR/epub-multi-rend-11/ で規定されているメカニズムによってパッケージ文書を使い分けることができます。

パッケージ文書の名前は任意ですが、拡張子には`.opf` (Open Packaging Format) を使うことが多いようです。パッケージ文書を配置するフォルダーも (`META-INF`の外であれば) どこでも構いません。

パッケージ文書の概形は大抵次のようになります。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         version="3.0" unique-identifier="pub-id">
  <metadata> <!-- [...] --> </metadata>
  <manifest> <!-- [...] --> </manifest>
  <spine> <!-- [...] --> </spine>
</package>
```

- `version` (必須) の値は (EPUB 3規格のマイナーバージョンによらず) `3.0`です
- `unique-identifier` (必須) の値は後述の`dc:identifier`のIDです
- `metadata`と`manifest`と`spine` (すべて必須) はこの順番である必要があります

## `metadata`
`metadata`には書誌情報などのメタデータが記述されます。メタデータの記述にはDublin CoreやEPUB独自の語彙が使われます。

```xml
<metadata>
  <dc:title>サンプル電子書籍</dc:title>
  <dc:language>ja-JP</dc:language>
  <dc:identifier id="pub-id">
    urn:uuid:d2ba8739-4bf9-4ab3-80de-a43aec20f2ac
    <!-- or urn:isbn:XXX-XXX-X-XXXXX-X -->
  </dc:identifier>
  <meta property="dcterms:modified">
    2024-07-20T03:00:00Z
  </meta>
  <!-- [...] -->
</metadata>
```

- 名前空間`http://purl.org/dc/elements/1.1/`に属する語彙は`metadata`直下に直接記述されます
- 名前空間`http://purl.org/dc/terms/`に属する語彙は`meta`要素を使って記述されます
- 必須メタデータは次の４つです
    - `dc:identifier`
    - `dc:title`
    - `dc:language`
    - `dcterms:modified`
- その他の語彙については以下のページを参照してください
    - https://www.w3.org/TR/epub-33/#app-meta-property-vocab
    - https://www.w3.org/TR/epub-33/#app-rendering-vocab
    - https://www.w3.org/TR/epub-33/#app-overlays-vocab

## `manifest`
`manifest`では書籍に含まれるすべてのリソースが列挙され、メディアタイプが関連付けられます。ここで列挙されていないリソースへのアクセスは拒否される可能性があります。

```xml
<manifest>
  <item id="toc-main" href="toc/main.xhtml" media-type="application/xhtml+xml"
        properties="nav"/>
  <item id="preface-main" href="preface/main.xhtml" media-type="application/xhtml+xml"/>
  <item id="preface-illust" href="preface/illust.png" media-type="image/png"/>
  <!-- [...] -->
</manifest>
```

- `id`、`href`、`media-type`は必須です
- `properties`に記述できる語彙は以下の通りです (https://www.w3.org/TR/epub-33/#app-item-properties-vocab)

  | 名前 | 説明 |
  |:-:|:-|
  | `cover-image` | 表紙 |
  | `mathml` | MathMLを含むリソース |
  | `nav` | EPUBナビゲーション文書 |
  | `remote-resources` | リモートに存在するリソース |
  | `scripted` | スクリプトを含むリソース |
  | `svg` | SVGを含むリソース |

## `spine`

`spine`はEPUB内容文書の読書順序を指定します。EPUB内容文書への参照をそれが読まれる順番に列挙します。

```xml
<spine page-progression-direction="ltr">
  <itemref idref="toc-main"/>
  <itemref idref="preface-main"/>
  <!-- [...] -->
  <itemref idref="notes-main" linear="no"/>
</spine>
```

- `page-progression-direction`はページ送りの方向を指定します
- 通常の読書順序から外れているリソース (注釈や解答例など) は`linear`の値を`no`に設定します
- `properties`にEPUB内容文書のプレゼンテーションに関する情報を記述することができます (https://www.w3.org/TR/epub-33/#app-rendering-vocab)
【xcode/swift】Firebase Authenticationを使ったユーザー新規登録機能（メールアドレス＆パスワード）

この記事は自分の備忘録のために書いています。

# 環境
- Xcode15.0.1
- Swift 5

# 前提
以下を前提とする
- firebaseでプロジェクトを作成している
- firbeaeのプロジェクトとxcodeのプロジェクトを紐づけている
- firebaseのプロジェクトのGoogleService-infoをxcodeのプロジェクトにダウンロードしている
- xcodeのプロジェクトにfirebase sdkをインストールしている
- AppDelegate.swiftに'FirebaseApp.configure()'の設定をしている

# Story Board
①メールアドレス入力用とパスワード入力用としてUITextFieldでを追加する
②パスワード入力用のUITextFieldはText Input TraitsのSecure Text Entryにチェックを入れる
③登録ボタンとしてUIButtonを追加する

# Register View Controller
```
import UIKit
import FirebaseAuth

class RegisterViewController: UIViewController {

    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var registerButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // ここでUIの初期設定を行うことができます
        setupKeyboardDismissal()
    }

    @IBAction func registerButtonTapped(_ sender: UIButton) {
        guard let email = emailTextField.text, !email.isEmpty,
              let password = passwordTextField.text, !password.isEmpty else {
            // 入力が不完全な場合は、ユーザーに通知する
            showAlert(message: "メールアドレスとパスワードを入力してください")
            return
        }

        // Firebase Authenticationを使用して新しいユーザーを作成する
        Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
            if let error = error {
                // エラーメッセージをローカライズして表示する
                let localizedErrorMessage = NSLocalizedString(error.localizedDescription, comment: "")
                self.showAlert(message: "登録に失敗しました: \(localizedErrorMessage)")
                return
            }

            // 登録が成功した場合、必要に応じてユーザーを次の画面に遷移させる
            self.showAlert(message: "登録に成功しました！")
            // 例: self.performSegue(withIdentifier: "goToNextScreen", sender: self)
        }
    }

    // アラートを表示するヘルパー関数
    func showAlert(message: String) {
        let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "OK", style: .default))
        present(alertController, animated: true)
    }
    
    // キーボードを閉じるためのセットアップ関数
    func setupKeyboardDismissal() {
        // Viewにタップジェスチャーを追加
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        view.addGestureRecognizer(tapGesture)
    }
    
    // キーボードを閉じるための関数
    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}
```

# エラー文言のローカライゼーション
①PROJECTのInfoのLocalizationsでJapaneseを追加してDefaultに設定する
②Localizable.stringsを作成する
```
"The email address is badly formatted." = "メールアドレスの形式が正しくありません。";
"The password is invalid or the user does not have a password." = "パスワードが無効であるか、ユーザーにパスワードがありません。";
"The email address is already in use by another account." = "このメールアドレスは既に使用されています。";
```
【python】if __name__=='__main__' を理解したい

# 概要
pythonの```if __name__='__main__'```の使い方がわからないので，調査しました．

# 背景
pythonに触れ始めてから3.4年も経つのにちゃんとコードを書けないのが恥ずかしくなってきたので記事に書いてわからないを公開していこうという気持ちになりました．．．
コードの冗長さについて考えずにコードを書いて動かすことはできるけれど，関数やその一歩先を行ったコードが書けないので，克服したい．
初めてこのような記事を書くので拙い部分があるかもしれませんが，よろしくお願いします．
最近はサマーインターンの申し込みに明け暮れていますが，コーディングテストで敗北しているので頑張ってお勉強していきたいと思います．

# 本題
python でよく登場するこちらのおまじない
```
if __name__=='__main__'
```
理解したいです．

# ChatGPT-4oの回答
if ``__name__ == '__main__'``は、Pythonプログラムで非常によく使われる構造です。これを理解するには、Pythonプログラムがどのように実行されるかを知る必要があります。以下に、初学者向けに簡単に説明します。

**Pythonプログラムの実行方法**
Pythonプログラムは2つの方法で実行されることがあります。

・スクリプトとして直接実行される場合
スクリプトとして直接実行されるとき、Pythonインタープリタはそのファイルの中身を読み込み、上から順に実行していきます。このとき、そのファイルの``__name__``という特殊な変数には``'__main__'``という値がセットされます。

・モジュールとしてインポートされる場合
モジュールとして他のファイルからインポートされる場合、そのファイル内のコードも読み込まれますが、このときの``__name__``変数にはファイル名（例えば、my_module.pyなら'my_module'）がセットされます。

**``if __name__ == '__main__'``の役割**
この構造を使うと、スクリプトがどのように実行されているかを判断し、それに応じて動作を変えることができます。具体的には、スクリプトが直接実行された場合にのみ特定のコードを実行し、モジュールとしてインポートされた場合にはそのコードを実行しないようにできます。

**なぜ使うのか？**
再利用性の向上: 同じコードをスクリプトとしても、モジュールとしても使えるようにするため。
可読性の向上: どのコードがスクリプトの実行時にのみ必要かが明確になるため。

**まとめ**
```if __name__ == '__main__'```は、スクリプトが直接実行されているか、他のモジュールからインポートされているかを判別するための構造です。これにより、スクリプトが再利用しやすくなり、コードの可読性が向上します。

なるほど．．．？この構造のメリットは分かりましたが，サンプルがわかりにくかったので，記事を漁りました．

# 参考記事
こちらの記事のサンプルを実行したらどのように動いているのかが理解できました！
とてもわかりやすい記事です．

https://qiita.com/soicchi/items/45ac8e2006361126b023

# わかったこと
関数を記述して呼び出すだけのpyファイルをimportすると，importした時点で実行までされてしまうようです．普通はpyファイルをimportした後，任意の場所でモジュールを呼び出したいはずです．そのため，import時点でファイルの中身が実行されないようにするための構造ということでした．
対して，pyファイルを直接ターミナルで実行する場合は，そのままスクリプトが上から下に実行されるだけのようです．なるほど，確かに便利．
【CSS】特定の子要素にフォーカスがない場合に親要素にスタイルを適用する方法

以下のように記述すると特定の子要素にフォーカスしていない場合にのみスタイルを適用できます。

```css
div:not(:has(要素:focus)) {
  
}

```

以下の場合、子要素のボタンにフォーカスしていなければ`div`の背景色が青になります。

```css
div:not(:has(button:focus)) {
  background: #0000ff;
}

```
GitHub ActionsでNo such file or directoryが出る

# 起きた問題
GitHub ActionsでcdしたらNo such file or directoryと出た

今回の作成したyaml
```
name: Sample
on:
  push:
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - run: cd directory
```

結果
```
Run cd directory
/home/runner/work/_temp/123456a-a111-2222-33ff-787877878dedadd.sh: line 1: cd: directory: No such file or directory
```

# 原因と解決策
原因は現在のワークフロー(GitHub Actions)がリポジトリにアクセスできないから。
解決するには、actions/checkout@v4を追加してリポジトリの内容をcheckout(取得)します。
```
name: Sample
on:
  push:
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    - uses: actions/checkout@v4
    steps:
    - run: cd directory

```
これで自分のリポジトリにあるファイルを参照できます。

# 最後に
パイプラインに取り掛かって最初にハマりそうな問題だったので、誰かの助けになれば幸いです。
【Python3】mod7占い (paizaランク S 相当)：アルゴリズム付きの解説

https://paiza.jp/works/mondai/s_rank_skillcheck_sample/mod7

まず、問題の要件を詳しく分析し、アルゴリズムを設計します。

### 要件分析

**問題の概要:**
- 与えられたカードの整数から、異なる3枚を選んでその和が7で割り切れる組み合わせの数を求める。

**入力:**
- 最初の行にカードの枚数 `N` が与えられる。
- 次の `N` 行に各カードの整数が与えられる。

**出力:**
- 和が7で割り切れる3つの異なるカードの組み合わせの数を一行で出力する。

### アルゴリズム設計

1. **入力の読み取りと初期化**
    - `N` を読み取る。
    - カードの整数をリスト `a` に格納する。

2. **カードの整数の分類**
    - 各整数を7で割った余りを計算し、余りごとにカウントするリスト `a_mod` を作成する。`a_mod[i]` は余りが `i` である整数の個数を表す。

3. **組み合わせの列挙**
    - 余りが `(i, j, k)` で、その和が7で割り切れるすべての組み合わせを列挙する。

4. **組み合わせの数え上げ**
    - 各組み合わせに対して、条件に従って組み合わせの数を計算する。
    - 特殊なケース (例えば、`i == j == k`) などを考慮して計算する。

### 擬似コード
**擬似コードのステップ:**

**ステップ1: 入力の読み取りと初期化**
```python
n = int(input())
a = [int(input()) for _ in range(n)]
```

**ステップ2: カードの整数の分類**
```python
a_mod = [0] * 7
for num in a:
    a_mod[num % 7] += 1
```

**ステップ3: 組み合わせの列挙**
```python
mod7_combinations = []
for i in range(7):
    for j in range(i, 7):
        for k in range(j, 7):
            if (i + j + k) % 7 == 0:
                mod7_combinations.append((i, j, k))
```

**ステップ4: 組み合わせの数え上げ**
```python
ans = 0
for comb in mod7_combinations:
    i, j, k = comb
    if i == j == k:
        ans += a_mod[i] * (a_mod[i] - 1) * (a_mod[i] - 2) // 6
    elif i == j:
        ans += a_mod[i] * (a_mod[i] - 1) // 2 * a_mod[k]
    elif j == k:
        ans += a_mod[i] * a_mod[j] * (a_mod[j] - 1) // 2
    elif k == i:
        ans += a_mod[i] * a_mod[j] * (a_mod[k] - 1) // 2
    else:
        ans += a_mod[i] * a_mod[j] * a_mod[k]
```

### 完成したコード
以下に完成したPythonコードを示します。

```python
# utf-8
n = int(input())

a = [0] * 7
for _ in range(n):
    a[int(input()) % 7] += 1

mod7 = []
for i in range(7):
    for j in range(i, 7):
        for k in range(j, 7):
            if (i + j + k) % 7 == 0:
                mod7.append((i, j, k))

ans = 0
for group in mod7:
    i, j, k = group
    if i == j == k:
        ans += a[i] * (a[i] - 1) * (a[i] - 2) // 6
    elif i == j:
        ans += a[i] * (a[i] - 1) * a[k] // 2
    elif j == k:
        ans += a[i] * a[j] * (a[j] - 1) // 2
    elif k == i:
        ans += (a[k] - 1) * a[j] * a[k] // 2
    else:
        ans += a[i] * a[j] * a[k]

print(ans)
```

### 結論
このアルゴリズムは、各カードの整数を7で割った余りを使って、和が7で割り切れる3つの異なるカードの組み合わせを効率的に数え上げます。各組み合わせに対する処理を最適化し、大規模な入力に対しても適切に動作するように設計されています。
Copernicusの処理結果をSolarisのビューポートで確認する(Slap comp機能の紹介)

![slapcomp_eyecatch.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/6708041f-def9-ae97-3e71-a5781a55e9f3.gif)
# はじめに
前回に引き続きCopernicusネタです。

https://qiita.com/Magryllia/items/bf672aa620e86a833eab

今回はもう少し実用的に、KarmaとCopernicusを組み合わせて使う際にSlap Compという機能が便利だったので紹介です。
本記事で使用しているバージョンは`20.5.278`です。
# ベースシーン
とりあえず適当にこんなシーンを用意しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/3299d5a8-2a03-805c-84f2-afb0abb5c83a.png)

# Slap Comp Import
CopNetを作成し、Slap Comp Blockを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/a391fadf-42e4-dc0d-5a2c-f9b7a3c4c941.png)
Slap Comp Importは最後にビューポートのKarmaでレンダリングした結果を見ることができます。
Slap Comp Importにディスプレイフラグを立てた状態で、
SolarisでKarma CPUやXPUのビューにしてグリグリ動かすとComposite Viewもリアルタイムで更新されていることが分かります
![slapcomp_slapCompImport.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/75fde312-92dd-3113-5061-410ec8b559ca.gif)

Karma Render Settingsで設定したAOVをCopernicusに渡すことができます
試しにNとShadowを追加します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/d2412478-9619-671e-5cc8-fba96c2813af.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/df1d9dd4-513b-6160-b963-540ba62256df.png)
Slap Comp Importの`Add AOVs from Last Render`をクリックすると、NとShadowが追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/a0a7d14c-beef-fe89-797e-3337e11bda59.png)

Composite ViewからそれぞれのAOVを見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/b2e8e954-9f60-4e4b-3d9f-c26e7b389b0d.png)

# SolarisでSlap Compを表示する
適当にBlockの中でコンプを作ります
<!-- Solaris側で表示するにはBlockの中でコンプを組む必要があります。 -->
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/09ded54b-d377-bbf5-c474-b41dccd161af.png)
Block Endの`Register as Slap Comp Block`にチェックが入っていることを確認します
ちなみにコンプをコンパイルできる場合は`Enable Comiling`を有効にしたほうが速いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/2ffe4b12-6d4d-ef8e-9d38-87807337529a.png)
SolarisのScene View右側のバーにある赤丸のボタンをクリックすると、Copernicusと同じコンプが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638853/4cf987ff-1449-b94f-e230-fe6acec42e54.png)
# おわりに
ルックデブが捗りそうです
VEX ShaderやMaterialXはあまりNPR表現に強くない印象なので、Copernicusも活用していきたいです

# 参考文献

https://www.sidefx.com/docs/houdini/copernicus/slap_comp.html

https://youtu.be/tzmrJpAFZ00?si=BIO3K12UmBOy7fFk
【メモ】プルリク単位について：自分なりの目安

## 概要
- プルリクを出す粒度について、悩んだので簡単にまとめて言語化したい

## 現状の分析

### 今の開発の流れ

現状をざっくりとまとめると、
1. Git・GitHubで管理している
1. コードを書くのは基本的に自分のみであり、メンターのサポートがつく状況である
1. `プルリクエスト（以下PR）`⇒`コードレビュー`⇒`マージ`の流れ

となっている

### 問題１：PRの肥大化

新規の機能を開発する場合は`機能ごとにブランチを切るようにしている`が、機能開発が想定よりも多くのファイルに依存する場合や新規ファイルの作成など様々に影響を与えてしまい、`PRが大きくなる問題がある`

### 問題２：PRの目的の分散

ブランチをより細かく小目標ごとに切ることで、PRの肥大化を抑えることが可能であるがPR回数が多くなってしまうため、`機能開発などの大目標におけるまとまりがなくなってしまう問題がある`

### 問題３：多分コミット粒度がでかい

PRを分割しようとしたところ、ある程度動く形でコミットをする関係でコミット≒PRとなってしまう問題がある
コミット単位に関してはまだ粒度の目安がはっきりと出せていないため、基準をつけながら調整したい

自分の場合は、この[記事](https://qiita.com/jnchito/items/40e0c7d32fde352607be)の意見１と２の方針でやっている状態です。ただその1機能のイメージがでかいことが問題なので、意見４の
>大きな機能を実装する前はTODOリスト（例：カラムを追加する、計算ロジックを実装する、画面を作成する、etc）を作成する

あたりを参考に機能の分割を行うべきと思いました

## PRに対する考え方

### PRに含まれるコミット数に関しては基本的に考慮しない

タイポの修正などまとめられるコミットの場合はまとめた方が良いが、基本的にコミットに関してはある程度細かく進めていくことで、どのように進めていったか歴史が分かりやすいので、細かくコミットしていきたい

### PRに含む変更のあるファイルは10ファイル以内程度

renameやmove、大量のタイポの修正などは専用のPRを作成し10ファイルは超えるが、影響範囲を特定しやすいように意識する

それ以外の場合は、10ファイル以内に収まる程度にがレビュアーが**レビューしやすい限界**とのこと

10ファイルを超える編集である場合は、編集の目的を分割することが可能なことが多いので目安とする

### まとめブランチを作成する

https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow

いわゆる`Gitflow`の考え方で、`develop`や普段作成しているブランチから、機能開発など用のブランチを作成し、それをさらに機能に必要なテスト・フロント・バック...etcとブランチを切り、機能開発用のブランチにPR・マージを繰り返し、機能開発が終了したタイミングでdevelopにマージするイメージである

このように`Feature（まとめ）ブランチ`を作成することで、PRが細かくなったとしてもどこからが目的の機能開発の内容かわかりやすくまとめることが可能である


## まとめ
PR・コミットに関しては、いろいろな考え方がある部分なのでチームの人との共通認識が重要であるが、チームの流儀に慣れるまではコミット粒度などを考えると、開発にかかる以外の場所の部分に意識を多く向けることになり疲れるかもなと感じた、、、
Discord.js v14でのチャンネル指定

こんちゃ、りょうです。
ちょっとわかりにくいことしてる人見かけたので忘れないように書いとこうかと思って。

### discord.js v14のチャンネル指定
discord.js v13で使用されていた`isText()`や`isVoice`が削除されまして。
かわりに**ChannelType**を使うようになった
```js
   const { ChannelType } = require("discord.js")
   /**
   なんちゃらかんちゃら
   **/
      if (channel.type === ChannelType.GuildText){
      //...
```
こんな感じ。
一応整数値でも表せるけどこっちのほうがわかりやすいとおもう。

### よく使われるやつの対応表

| Left align          | Right align | 整数値 |
|:--------------------:|:------------:|:-----:|
|  テキストチャンネル    | `GuildText `  |   0   |
|  DM                 |    ` DM    `  |   1   |
|  ボイスチャンネル      | `GuldVoice `  |   2   |
|  グループDM           | `GroupDM    `|    3  |
|  カテゴリー           | `GuildCategory`|   4  |
| アナウンスチャンネル    | `GuildAnnounce `| 5 |
| 公開スレッド          | `PublicThread`| 11|
| 非公開スレッド|`PrivateThread`|12|
| ステージチャンネル|`GuildStageVoice`|13|
| フォーラム|`GuildForum`|15|
|画像専用チャンネル|`GuildMedia`|16|

### 一応整数値版
テキストチャンネルの場合↓
```js
      if (channel.type === 0){
      //...
```
これで一応はできるけど読みにくいし普通にChannelType使おう()

### まとめ
読みやすいのが一番。

**Discord荒らしなどの情報や対策の共有する自鯖↓**
https://discord.gg/ESRGwGQhxc
Keycloak に Identity Provider / OIDC でログインすると Invalid username or password. になる問題

# issue

Keycloak に OIDC client として Identity Provider を追加してログインしようとしたところ、エラーが出ました。

> Invalid username or password.

OIDCの認証は完了して、Keycloakのlocal userと何かをするところでこけてる感じです。
試しにuserを手動で作ってみてもエラーは変わらない。
userが持つ Identity provider links に手動でlinkを追加してあげると、ログインに成功します。
userとIdPをlinkすることができていないようです。

# Solution

> Admin console > Authentication > first broker login

ここにある `Handle Existing Account` を `Alternative` にしたら解決しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24737/c311f017-649b-dea8-fb17-8cac517fd937.png)

ログインしたユーザは local userとして作られ、IdP links もきちんと設定されていました。

すっきり！