OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS re:Invent2024】体調を崩さないための準備と心得

# 1. はじめに
アイレット株式会社の浅岡です。

本記事では、アメリカはラスベガスで開催されているAWS re:Invent2024に現地参加した際、体調を崩した時に考えていたことについてお話しします。

今後、re:Inventに参加される方が一人でも体調を崩さず、充実した時間を過ごせるよう、この体験が少しでもお役に立てれば幸いです。

# 2. AWS re:Inventでの出来事
海外経験がなかった私は、初めての現地参加となるAWS re:Invent 2024に向けて、準備を万全にした(つもり)でした。

私が体調を崩すまでに至る経緯は次のような流れでした。
### 1日目
日本からラスベガスへ飛行機で移動しました。
出発地点の成田国際空港では、カツカレーを食べられるぐらい元気でした。
### 2日目（ラスベガスへ到着した日）
道中の飛行機であまり睡眠が取れなかったので、少し寝不足感があったものの、特に体調に問題はなく、バッチの受け取りや現地の食事を楽しみました。

### 3日目
朝から腹痛を感じ始めました。
最初はよくある一時的なものだと思っていたので、CAESARS FORUMで朝食を取った後、8:00開始のセッションに参加しました。
しかし、腹痛が徐々にひどくなったため、セッション聴講後、その後の予定もあったのですが、やむを得ずホテルに戻り、持参していた胃腸薬を飲んで安静にしました。
夜になる頃には熱も出始め、腹痛と合わせて頭痛や関節痛、軽い嘔気まで合わさり、辛い時間を耐えるような状態でした。

### 4日目以降
ピークは3日目だったようで、頭痛・関節痛は治りましたが、腹痛と軽い嘔気が残っており、2日目のような活発な活動はできない状態で過ごしました。

なんとか、短時間のセッションや軽い食事、休み休みEXPOを回ることはできましたが、体調が万全であれば、と思わされる数日でした。

結局帰路に着くまで症状が完全に回復することはなく、じわじわと続く腹痛に苦しみながらの帰国となりました。

# 3. 体調管理の重要性
re:Inventのような大規模イベントでは、体調管理の重要性を改めて痛感しました。
特に海外では環境の変化が大きく、長時間の移動や時差、寒暖差など、体調を崩す要因が多くあります。

私も体調を崩したことで予定していたセッション参加やイベント参加の機会を逃し、貴重な体験を十分に楽しめない場面がありました。
事前に万全な準備をしていたつもりでも、想定外の事態に備える重要性を実感しました。　

# 4. 事前の備えが一番大事
今回の経験を通して、事前の準備がどれだけ重要かを痛感しました。

私は普段から体調を崩しやすい方なので、体調管理については十分に準備をしたつもりでした。
しかし、実際に体調を崩してみると、準備が不十分だったと思わされる点がいくつか見えてきました。

私があればよかった・もっと持っていけばよかったと思ったものは以下です。
- 普段使っている胃薬（正露丸等）
- 整腸剤（新ビオフェルミンS錠等）
- 解熱鎮痛剤（バファリン等）
- 体温計
- 熱さまシート
- 流動系・消化の良い軽食（粉末スープ類、インスタントうどん等）
    - インスタントうどんは外国に持っていけるらしい。
- 柔らかいトイレットペーパー
    - お腹を下した時は外国のトイレットペーパーは硬いので辛い。

特に解熱鎮痛剤は滞在日数分持っていくべきだなと感じました。
ずっと腹痛は辛い。。。

ちなみに、持っていっておいてよかったと思ったものは以下です。
ご参考までに。
- 折りたたみ電気ケトル
    - スープ類を飲んだり、部屋を加湿するために。
- のどぬ〜るぬれマスク
    - 喉を乾燥させないように。乾燥すると風邪にもかかりやすくなるため。
- 動きやすい寝巻
    - 体を冷やさない&寝る時にも辛くない。

あと可能であれば、現地で何かあった時に相談できる人を作っておくのも大事だなと感じました。
私の場合は、会社の同僚が現地で色々調達してきてくれました。
一人旅だったらと考えるとゾッとしますね。

# 5. まとめ
どれだけ準備しても「想定外」は起こるもの。だからこそ、万が一を想定して、全日程をカバーできる準備が本当に大切だと思いました。

今後AWS re:Inventに参加される皆さんも、体調管理への備えを持って、全力で楽しんでくださいね！
拡散モデルを活用した次世代動画生成と理解：Divot論文の詳細解析

# Divot: 拡散モデルによる動画理解と生成を統一する次世代フレームワーク

今回は、「Divot: Diffusion-Powered Video Tokenizer for Comprehension and Generation」という革新的な研究をご紹介します。この研究は、動画データの複雑な空間-時間的特徴を捉え、理解と生成を同時に実現する技術を提案しています。

---

## 論文情報
- **タイトル**: Divot: Diffusion-Powered Video Tokenizer for Comprehension and Generation
- **リンク**: [GitHubリポジトリ](https://github.com/TencentARC/Divot)
- **発表日**: 2024年12月5日
- **著者**: Yuying Ge, Yizhuo Li, Yixiao Ge, Ying Shan
- **DOI**: N/A

---

## 背景と目的

動画データは、静止画像データに比べて次のような特徴を持ち、より高度な技術が必要とされます：
- **空間的特徴**: 各フレームの詳細な情報を解析する必要があります。
- **時間的動態**: フレーム間の変化や相関関係を考慮する必要があります。
- **データの高次元性**: 動画は多くのフレームを含むため、計算コストが膨大です。

これまでの研究では、主に離散型トークナイザーを使用してきましたが、この手法には以下のような課題があります：
1. **時間的相関の喪失**: 各フレームを独立したトークンとして扱うため、動画全体の時間的一貫性を維持するのが難しい。
2. **生成精度の低下**: 離散化により、元のデータの特徴が損なわれる可能性があります。

本研究では、連続的な動画表現を採用し、拡散モデルを活用することで、これらの課題を解決します。

---

## 提案手法

### Divotトークナイザー

Divotトークナイザーは、動画データを自己教師付きで学習し、効率的な空間-時間的表現を取得します。

- **構成要素**:
  1. **Vision Transformer（ViT）**:
     - 各フレームの高次元特徴を抽出。
     - 空間的特徴を詳細に学習。
  2. **空間-時間トランスフォーマー**:
     - 時間的相関を考慮し、フレーム間の統合を行う。
  3. **Perceiver Resampler**:
     - 冗長なデータを圧縮し、効率的なトークン化を実現。

- **拡散プロセスの詳細**:
  1. 動画データにノイズを付加し、デノイズを通じて学習。
  2. クロスアテンションを活用して、トークン間の関連性を強化。
  3. 最終的に、スパースなフレームから動画全体の表現を再構成。

### Divot-LLM

DivotトークナイザーをMistral-7Bモデルと統合し、次のタスクを実現します：
- **動画理解**:
  - 次単語予測タスクで、スパースなフレームからテキストを生成。
  - 動画の時間的一貫性を保ちながら意味的な理解を実現。
- **動画生成**:
  - Gaussian Mixture Model（GMM）を使用して、動画表現の確率分布をモデル化。
  - GMMからサンプリングし、現実的な動画を生成。

---

## 実験結果と分析

### データセットと環境設定
- **トークナイザー学習**:
  - WebVid-10M（10万動画）、Panda-70M（70万動画）。
- **評価データセット**:
  - MSR-VTT、EgoSchema、Perception-Test。
- **ハードウェア**:
  - NVIDIA A100 GPU（32枚構成）。

### 定量的評価
- **動画理解**:
  - EgoSchemaにおける精度：**58.3%**。
  - MSVDの精度：**76.4%**。
- **動画生成**:
  - CLIPスコア：**0.2938**（他モデルと比較して競争力あり）。
  - Frechet Video Distance（FVD）：**301.4**。

### 定性的評価
生成された動画は以下の特徴を持ちます：
1. テキストプロンプトに忠実な内容。
2. フレーム間の時間的一貫性。
3. 高い視覚品質。

また、「Curious George」データセットでファインチューニングを行い、物語性のある動画生成を実現しました。

---

## 学術的意義と応用可能性

### 学術的意義
- 拡散モデルを用いた自己教師付き学習により、空間-時間的特徴を高精度で捉える。
- 動画理解と生成を一つのフレームワークで統一する新たな可能性を示す。

### 応用可能性
- **教育**: 教材動画の自動生成。
- **エンターテインメント**: 映画やゲームシーンの作成。
- **監視**: 動画データのリアルタイム解析。

---

## 制約と今後の課題

### 制約
1. 長尺動画の生成には未対応。
2. 高い計算コストとリソース要件。

### 今後の展望
- 長尺動画生成への拡張。
- モデルの計算効率化。
- リアルタイム処理の実現。

---

この記事が、動画生成技術に興味を持つ研究者や実務者の参考になれば幸いです。ご質問やコメントがあれば、ぜひお寄せください。
レイアウトグループを使って画像を右詰・左詰めに配置する方法

## はじめに

HPのように並んだアイテムを配置し、オブジェクトが非アクティブになったときにも位置をずらさずに左右に詰める方法を備忘録も兼ねて解説します。

![スクリーンショット 2024-12-08 112823.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327956/9773b693-d1c1-3983-b5a5-374ff97dc5d1.png)
![スクリーンショット 2024-12-08 112834.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327956/9ad8553b-4042-5bfe-a286-8db28e7d4cd0.png)


## 配置
![スクリーンショット 2024-12-08 114552.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327956/41895b56-3275-3407-0496-0bb6b69e5e02.png)

まず、親となる```Image```を配置します。
なんとなく右上に置きたいので、右上固定になるようアンカーなどで位置を調整します。
この```Image```は位置を確認するために置いているだけなので特にスプライトは設定しなくて大丈夫です。

## コンポーネント追加

![スクリーンショット 2024-12-08 114837.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327956/8c4c8bb3-dc41-a239-f015-13579ccfaa94.png)

今回はアイテムを横並びにしたいので以下のコンポーネントを追加します。
<dl>
    <dt>1.Horizontal Layout Group</dt>
        <dd>子オブジェクトを横方向に整列してくれます。</dd>
        <dd>縦に並べる場合Vertical Layout Groupにしてください。</dd>
        <dd>今回値は変えても特に意味がないので設定しません。Spacingはお好みで。</dd>
    <dt>2.Content Size Fitter</dt>
        <dd>オブジェクトのサイズに合わせて可変させるのに便利です。</dd>
        <dd>今回横幅を可変させたいのでHorizontal FitをPrefferd Sizeにします。</dd>
        <dd>これを設定すると先ほどの白い```Image```が見えなくなりますが問題ありません。</dd>
</dl>

## 子を追加
![スクリーンショット 2024-12-08 115523.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327956/6d08e8e7-9874-8928-3d72-17916cc7063c.png)
先ほどの親オブジェクトの下に好きな画像を子として置きます。
今回はHPなので５つくらい置いてみました。
背景の白い部分は親のスプライトですが、きちんと配置できていることを確認できたため```Remove Component```してください。
## 親オブジェクトのPivotを調整する
この状態で子を非アクティブにすると**右詰め**または**中央詰め**の状態になると思います。
右詰めのままでも良い場合もありますが、仕様によっては左詰めが求められることがあるかもしれません。

![スクリーンショット 2024-12-08 120653.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327956/5503bed9-3428-96e0-5356-7645f753affd.png)

* 左詰めにする場合は親の```Pivot```のXを0に設定
* 右詰めにする場合は親の```Pivot```のXを1に設定

すると子を非アクティブにしたとき右、または左から消えるように調整ができます。

## おわりに
今回は```Layout Group```と```Content Size Fitter```を組み合わせたUI配置を行いました。
UnityのUI配置はまだまだ仕様や便利機能を把握しきれていないのでもっと理解を深めたいところです。
lessコマンドの結果を色付けする

# はじめに
コマンドラインでファイルをちょっと見たい時にlessコマンドを使いますが、やはりシンタックスハイライトが欲しくなります。
lessコマンドを色付けしてみたので、そのやり方を書きます。

# 環境
挙動確認した環境は以下です。

|対象  |バージョン  |
|---|---|
|zsh  |5.9 (x86_64-apple-darwin22.1.0)  |
|source-highlight  |3.1.9_5  |
|neovim  |v0.10.2  |

# 1. source-highlight
こちらを使います。
[GNU Source-highlight](https://www.gnu.org/software/src-highlite)

すでに紹介している記事が多くいるので省略しますが、自分は以下を参考にインストールしました。
https://sumito.jp/2019/06/20/source-highlight

## 使ってみた感想
特にデメリットはなく、悪くないのですが、やはりneovimやVSCodeなどのIDEに比べると色付けが弱いです。
例えば、 `.zshrc` などは色付けしてくれませんでした。

# 2. neovim
neovimにはlessやmoreのようにneovimを起動してくれるスクリプトが搭載されています。
https://neovim.io/doc/user/various.html#less

`$VIMRUNTIME/scripts/less.sh`にあります。
`$VIMRUNTIME`は以下で取得できます。

```sh
VIMRUNTIME=$(nvim --clean --headless --cmd 'echo $VIMRUNTIME|q' 2>&1)
```

公式サイトをみると `nvim --clean --headless --cmd 'echo $VIMRUNTIME|q'` でいいようなのですが、自分の手元では最後の `2>&1` をつけないと環境変数にパスが入りませんでした。

あとは
```sh
alias vless="$VIMRUNTIME/scripts/less.sh"
```
とエイリアスを設定すればOKです。
既存のlessの挙動を置き換えたい場合は以下のようにしましょう。

```sh
alias -g less='vless'
```

## 使ってみた感想
さすがneovimの色付けだけあって、source-highlightでは無理だったファイル形式も不満のない色付けをしてくれます！
![スクリーンショット 2024-12-09 0.35.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169996/581c4218-dbb7-1a61-35ad-e70e094989fb.png)

少しlessよりも起動に時間がかかる気もしますが、気になるレベルではありません。
ファイルサイズがとても大きいものをlessするともしかしたら大きな差になってくるかもしれないです。

## less用のneovim設定はできなかった
neovimをlessとして使ってみると、neovimのようにカーソルがあるなどlessと異なる挙動があります。
これを変えたければ、 `LessInitFunc` を使うとneovimをlessとして使う場合だけ設定を適用できます。

```vimscript
func LessInitFunc()
  set nocursorcolumn nocursorline
endfunc
```

ただ、私はneovimの設定をVimScriptではなくluaで書いているのですが、luaで `LessInitFunc` をどう設定するかわかりませんでした。
試してないのですが[luaからVimScriptを読める](https://neovim.io/doc/user/lua-guide.html#lua-guide-vimscript)らしいので、それで実現はできそうですが、そこまでするほどではないかと思いデフォルトの挙動で使っています。

# 終わりに
色がつくとファイルが読みやすくなって効率が上がるのでおすすめです。
興味ある方はぜひ一度試してみてください！

# 2025/4/12 追記
ある日突然動かなくなったなと思っていたら、パスが `$VIMRUNTIME/macros/less.vim` から `$VIMRUNTIME/scripts/less.vim` に変わってました :sweat_smile: 

```sh
$VIMRUNTIME/scripts/less.vim
```

https://neovim.io/doc/user/various.html#less申し訳ありませんが、そのURLの内容を直接翻訳することはできません。ただし、特定のテキストを提供していただければ、その翻訳を行います。
AlfreadのWorkflowからBetterDisplayを操作する

ファイルはココ

https://github.com/RepublicOfKorokke/Tools/blob/main/Alfread/BetterDisplay.alfredworkflow

Alfreadで`dd`と打つとListから操作できます。

![Screenshot 2024-12-09 at 0.28.56.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361273/f6f6c90b-e696-f651-cfe8-72d0027ee280.jpeg)

![Screenshot 2024-12-09 at 0.22.41.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361273/9769a7e6-3628-9210-61e1-8514aa0121bd.jpeg)

![Screenshot 2024-12-09 at 0.22.48.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361273/878f5f48-c580-0388-32bc-2416b1aad413.jpeg)


## やったこと
BtterDisplayのUIから操作するのが面倒なので、
AlfreadのWorkflowから以下の操作ができるようにした。
- 明るさの変更
- 配置の位置関係変更
    - 外部Display専用
    - MacのBuild in Displayに対して、左右どちらに置くか
- 接続状態のトグル
- NightShiftのトグル
- 解像度の変更 (2024-12-09 Update)

NightShift以外はどのDisplayにActionするか選べます。

シンプルなので自分好みにカスタマイズもしやすいはず。


## 使ったもの
### AlfreadのWorkflow

初心者なのでこんな便利なInputあるの知らなかった。

https://www.alfredapp.com/help/workflows/inputs/script-filter/



### BetterDisplay (Integration features, CLI)

CLIから操作できるの知らなかった。
Path通す別Appもbrewから入れられるけど、無駄なモノ無しで動かしたかったので使ってない。

https://github.com/waydabber/BetterDisplay/wiki/Integration-features,-CLI

### SF Symbols

アイコン用

https://developer.apple.com/jp/sf-symbols/

### Chat-GPT4o

BetterDisplayからDisplay一覧を取って
AlfreadのScript Filterが受け付ける形への変換を手伝ってもらった。
スクラムマスターは100点をつけない

この記事は[ZOZOアドベントカレンダー2024](https://qiita.com/advent-calendar/2024/zozo)シリーズ８の９日目の記事です。

# チームが成長するのは嬉しい

チームが自律し、成果も上がり、ビジネス的にも成功できるようになるのはチームにとっても、メンバーとしても、経営層もみんな当然うれしいことです。
大いに称賛すべきですね。

# スクラムマスターは一歩先を行く

チームがうまくいくことはもちろんいいことですが、スクラムマスターとしてはその一歩先を歩いているべきです。
メンバーがそこで満足してしまっては次がありません。

スクラムマスターとしては次の挑戦を大いに勧めるところです。

# 変化は常に起こる

チームの成長には段階があります。以下の図はタックマンモデルと言われている図です。
チームができる形成期から混乱期を超えて、徐々にパフォーマンスが上がっていく様子を表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150455/1a296dfa-f7fb-5cf7-9b90-d2827f455f6f.png)

この図上では機能期まで至ると散開期までパフォーマンスが上がり続けますが、チームの変化によって、形成期や混乱期に戻ることもあります。

たとえば、新メンバー加入やメンバーが抜けるとき、長期の休養でもありえます。

# 理想のチームをチームメンバーで考えてみる

一度メンバー全員参加で理想のチームとは何か？というのを話し合ってみることをおすすめします。

そして、毎週点数をつけてみて過去と比較していくと、チームの成熟度を見える化できます。

チームが成長するにつれて点数が上がっていく様子を見ることができますが、そこでチームに新メンバーが加入したとしたとき、今度はチーム全員で考えた理想のチームの定義に違和感が出てくると思います。

そのような経験からチームの変化によって形成期、混乱期に戻ることがあることを実感できると思います。
そのときはもう一度みんなで改めて理想のチームを話し合って見るのが良いでしょう。

# スクラムマスターは100点をつけない

変化はメンバーの変動によるものだけではありません。新しいプロダクトの開始や、そこまでの変化でなくても顧客が離れてきている、新規顧客が増えなくなってきているなどプロダクト要因の変化もあります。

顧客が離れてきていればアウトサイドインの施策を取る必要がありますし、新規顧客が増えなくなっていればインサイドアウトの施策が必要でしょう。プロダクトが続いていれば必ずそのような変化は訪れますし、チームにとっては状況によって動き方を変えていく必要があります。

そのようなときにメンバーがチームに100％満足してしまっていては変化についていくことができなくなってしまいます。

スクラムマスターはこのような変化を見越して常に100点をつけるのではなく、次の改善点、次の挑戦を見据えていきましょう。
[Delphi][小ネタ] CNG Random を使う

# Delphi の Random 関数

Delphi の Random 関数、デフォルトで提供されているアルゴリズムが[線形合同法](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%90%88%E5%90%8C%E6%B3%95)だけなんですよね。
まあ、多くの場合これで足りるんですけど、乱数の品質に関してはちょっと弱い。

でも Windows なら、Windows ならきっと何とかしてくれる！

# CNG Random
CNG とは Crypto Next Generation の略で、その名の通り[次世代の暗号化ライブラリ](https://learn.microsoft.com/ja-jp/windows/win32/seccng/cng-portal)群です。
従来の CryptoAPI を置き換える物になっています。

CNG が提供している API に [BCryptGenRandom](https://learn.microsoft.com/ja-jp/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom) という乱数を返す API があります。
この API が返す乱数は[暗号に利用可能な強度](https://ja.wikipedia.org/wiki/%E6%9A%97%E5%8F%B7%E8%AB%96%E7%9A%84%E6%93%AC%E4%BC%BC%E4%B9%B1%E6%95%B0%E7%94%9F%E6%88%90%E5%99%A8)を持った乱数です。

使い方は簡単で↓これだけで Result に乱数が返ります。

```delphi
function CNGRandom: UInt32;
begin
  if
    BCryptGenRandom(
      0,              // アルゴリズム・プロバイダのハンドル
      @Result,        // 乱数を格納するバッファのアドレス
      SizeOf(Result), // バッファのサイズ
      BCRYPT_USE_SYSTEM_PREFERRED_RNG // デフォルト乱数アルゴリズムを使用
    ) <> ERROR_SUCCESS
  then
    Result := 0;
end;
```

:::note info
BCRYPT_USE_SYSTEM_PREFERRED_RNG を使う場合はプロバイダのハンドルは 0 を指定します。
:::

これで、つよつよ乱数が手に入ります。
でもこんなに引数指定するの面倒なので、簡単に呼べるようにしましょう。

# Random32Proc 変数

System.pas に定義されている [Random32Proc](https://docwiki.embarcadero.com/Libraries/ja/System.Random32Proc) 変数の中身を入れ替えると、乱数プロバイダを変更できます。
これを先ほどの CNGRandom に変えます。

```delphi:乱数プロバイダの変更
Random32Proc := CNGRandom;
```
```delphi:乱数の使用
var R := Random(10); // CNGRandom が呼ばれる！
```
Delphi デフォルトの Random 関数を呼ぶと CNGRandom が呼ばれるようになります。
簡単～

# Unit 化
と、まあ BCryptGenRandom を簡単に呼べるようになったですが、実は CNG は Delphi では宣言されてないので定義なんかも書かないといけないんですよね。
なので、Unit 化しちゃいましょう

```delphi:PK.Math.CNGRandom.pas
unit PK.Math.CNGRandom;

interface

implementation

uses
  Winapi.Windows;

// CNG Random の定義
const
  LIB_NAME = 'bcrypt.dll';
  BCRYPT_USE_SYSTEM_PREFERRED_RNG = 2;

function BCryptGenRandom(
  hAlgorithm: THandle;
  pbBuffer: PByte;
  cbBuffer: ULONG;
  dwFlags: ULONG): HRESULT; stdcall; external LIB_NAME;

function CNGRandom: UInt32;
begin
  if
    BCryptGenRandom(
      0,
      @Result,
      SizeOf(Result),
      BCRYPT_USE_SYSTEM_PREFERRED_RNG
    ) <> ERROR_SUCCESS
  then
    Result := 0;
end;

initialization
  // Random で呼ばれる乱数生成器を CNGRandom に置き換える
  Random32Proc := CNGRandom;

end.
```

これを uses すると、Random を呼ぶと CNGRandom が呼び出されるようになります。

# サンプル

ほとんど意味はありませんが、1万回呼んで 0～9 の値がどの程度出てくるかカウントしてみます（乱数の品質がわかるとかそういう意味は全くないサンプルです）。

```delphi:サンプル
program CNGRandomSample;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Winapi.Windows,
  PK.Math.CNGRandom in 'PK.Math.CNGRandom.pas';

begin
  var Rs: array [0.. 9] of Integer;
  FillChar(Rs, SizeOf(Rs), 0);

  for var i := 0 to 10000 do
  begin
    var R := Random(10); // CNGRandom を呼び出す
    Inc(Rs[R]);
  end;

  for var i := 0 to High(Rs) do
    Writeln(i, ' ', Rs[i]);

  Readln;
end.
```

結果はこんな感じでした。

```console
0 988
1 1015
2 973
3 1001
4 997
5 995
6 985
7 1066
8 979
9 1002
```

# まとめ
セキュリティに重要な意味を持つ場合は BCryptGenRandom を使うといいですね。
そうでない場合はデフォルトの線形合同法でも一定の価値はあるでしょう。
個人的に良く使うのは [XorShift](https://ja.wikipedia.org/wiki/Xorshift) ですが…
JavaScriptの配列さんをちゃんと覚えたい

配列さんの嫌なところ

- `for`と`forEach`って何よ。`while`じゃ駄目なんかい
- `find`とか便利なメソッドが色々あるみたいやんけ。ちょっと吐き出してみーや

というまとめ

# ループ処理の種類と使いどころ

## while

```js
while(条件式){
  //処理
}
```

ループが「回数」ではないところがポイント。
例えば直前に定義した`let color`が`//処理`の中で`red`になるまでループとか。

こんなループ条件書いたら無限ループしそうで怖いけどｗ

## for

```js
for(let i = 0; i < chars.length; i++){
  //処理
}
```

「回数」を条件にループするやつ。一番頻繁に使うのが上記の配列の要素数`配列.length`で使うやつ。

## for..of

```js
for(const char of chars){
  //処理
}
```

配列を対象にした`for`を実装するときにオシャレに簡略化できる方法。
ただ`i`を別途使いたいなら話は別。

## for..in

曲者

```js
const langs = {
  Japan: "Japanese",
  America: "English"
};

for(const key in langs){
  console.log(key);
  console.log(langs[key]);
  console.log(langs.key);
}
```

```text:出力結果
Japan
Japanese
undefined
America
English
undefined
```

Perlでいうところの`keys()`関数みたいなもんで、オブジェクトのキーを取得できる。
なんだけど、取得したキーを使って値にアクセスするときは`langs.key`じゃない。`langs[key]`になる。なんでじゃ。

## forEach

```js:sample.js
const fruits = ["orange", "apple", "lemon"];
for(let i = 0; i < fruits.length; i++){
  console.log(fruits[i]);
}
```

```js:sample.js
const fruits = ["orange", "apple", "lemon"];
fruits.forEach((fruit) => {
  console.log(fruit);
})
```

いちいち`i`を定義しなくていい。あと`forEach`が関数ではなくて配列のメソッド、というところ。

# その他のメソッド

## find

配列の要素から条件に一致する要素を探し出す

```js
const numbers = [1, 2, 3, 4, 5, 6];
const result = numbers.find((number) => {
  //探索条件を書く
  return number % 3 === 0;
});

console.log(result);
```

```text:出力結果
3
```

探索条件の「結果」(`True/False`)ではなくて、Hitした値が返される。忘れそう。

```js
const charcters = [
  {name: "Ki2neudon", age: 38},
  {name: "TanukiSoba", age: 36},
  {name: "SioRamen", age: 42}
];

const result = characters.find((character) => {
  return character.age >= 40;
});

console.log(result);
```

```text:出力結果
{name: 'SioRamen', age: 42}
```

## filter

`find`の条件一致したやつ全部取り出すやつー

```js
const numbers = [1, 2, 3, 4, 5, 6];
const result = numbers.filter((number) => {
  //探索条件を書く
  return number % 3 === 0;
});

console.log(result);
```

```text:出力結果
(2) [3, 6]
```

## map

たぶん前回の記事？で書いた`Map`とは話が違う。紛らわしくない？
`return`の行で各要素に対して行う処理を書き、それを経た新たな配列が作られる。

```js
const numbers = [1,2,3];
const result = numbers.map((number) => {
  return number + 2;
});
console.log(result);
```

```text:出力結果
(3) [3, 4, 5]
```
【GAS】スクレイピングで抽出した結果をもとに通知を送る

## はじめに

スプレッドシートとGASを使って、なんらかのWebページの一部分を取得し、条件に合ってたら通知を送る！みたいなことをやろうと思います。チケットの空きやグッズの再販情報を誰よりも早く入手したいけど、ずっとサイトを監視するのは無理かも...って時などに使えるかもしれません。

※スクレイピングは迷惑をかけない範囲でやりましょう。
※スクレイピングダメだよーって明記してるサイトでスクレイピングをやるのはやめましょう。

## 情報を抽出しよう

簡単に使いまわせるよう、情報を取得したいURLなどはスプシ側に記載していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375387/209f51ce-26fc-307c-689e-ce21b924076c.png)


この例では、A2セルに**情報を取得したいページのURL**、B2セルに**XPath**を入れる想定です。

XPathは、
1. ページ上の取得したい情報を範囲選択して右クリック
2. 「検証」を選択
3. 選択されている部分で右クリック
4. 「XPathをコピー」を選択

という手順で取得できます。

そしてC2セルに、
~~~
=IMPORTXML(A2,B2)
~~~

と書いておけば、C2セルに指定した情報が表示されます！

## 通知を送ろう

「拡張機能」から「Apps Script」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375387/03beeae5-37e2-6115-eaa3-be1950ec8d96.png)


するとApps Scriptの画面に遷移するので、良い感じのコードを書いて通知を送れるよう設定してみましょう。ここではGmailに送る例を紹介します。

~~~js
function check_update(sheetname,xml_cell,key_cell,key) {
  //スプシ取得
  const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  //シート取得
  const sheet = spreadSheet.getSheetByName(sheetname);

  //IMPORTXMLが入っているセルの中身を一回消してまた上書きすることで、強制更新を行う
  const tmp=sheet.getRange(xml_cell).getFormulas();
  sheet.getRange(xml_cell).deleteCells(SpreadsheetApp.Dimension.ROWS);
  sheet.getRange(xml_cell).setValue(tmp);

  //抽出した値を取得
  const value = sheet.getRange(key_cell).getDisplayValue();
  const url = sheet.getRange("A2").getDisplayValue();

  //特定の値だったらGmailを送る
  if(value==key){
    const email = Session.getActiveUser().getEmail();
    GmailApp.sendEmail(email, sheetname+" "+value,url,{cc:"【メアド入れてね】"});
  }
}

function main(){
  //シート名指定
  const sheetname="【シート名入れてね】";
  
  //IMPORTXMLを入れたセルを指定
  const xml_cell="C2";
  
  //比較したい情報のセルを指定
  //今回はIMPORTXMLで取得した情報をそのまま比較しています
  const key_cell="C2";
  
  //キーを指定
  const key="【この値になったら通知したい！っていう値を入れてね】";

  check_update(sheetname,xml_cell,key_cell,key);
  
}

~~~

こんな感じで書いて保存してmain関数を実行すると、抽出した値によってメールが送られたり送られてこなかったりするかなと思います。
次に、main関数を定期的に行ってもらうために、トリガーを設定しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375387/eac7dd6b-3b9d-b40b-921e-312841faa22d.png)

左側から「トリガー」を選んで移動して...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375387/4a4fa407-2b62-fa3e-644c-5d5511389896.png)

なんかこんな感じで設定すればいけます。
「時間ベースのトリガーのタイプを選択」と「時間の間隔を選択」はお好みで選んでください。(迷惑かけない範囲でね)

こうすることで、自動で定期的にスクレイピングを行い、抽出した結果をもとに通知が送られるようになりました！

## おわりに
今回はお手軽なスクレイピング方法としてIMPORTXMLを使う方法を紹介しました。
もっとたくさんの情報を取得したい場合は、ライブラリを使うのがよいと思います。また、Gmailだけではなく、DiscordとかSlackにも送信できるのでいい感じに組み合わせて使ってみてください。

**法律を守ってよいスクレイピングライフを！**
AlmaLinuxにnode.jsを入れる

# はじめに
仮想環境上にAlmaLinux環境を構築できたので、本来の目的である
Firebase Hosting のデプロイ環境を作ってまいります。
と思ったけど、npmのインストールでハマったので、その準備編メモになります。

## node.jsのインストール
Firebase CLIをインストールしようとしたけど、npmなんてないよ？って
言われたので、version確認とその流れでインストール。

```
npm install -g firebase-tools
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826192/6e7a423e-e55f-0d57-35d0-34a0d6eba67f.png)

<br/>

めちゃ楽じゃん、と思っていたら、、怒られた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826192/9c313b64-6c80-6c16-ce68-6d99b76c667f.png)

<br/>

あきらめてdnfを使って、node.jsのインストールを行っていきます。
```
sudo dnf install nodejs
```
インストール対象パッケージが出てくるので、そのまま「y」を入力。

<br/>

すぐに完了となったので、npmのバージョンを確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826192/bb6bc4df-2989-1238-64fb-291a985a26a8.png)

おぉ、ちゃんとnpmも入っていますね。


## Firebase CLIのインストール?
では、気を取り直して、Firebase CLIのインストールを再度チャレンジ。
```
npm install -g firebase-tools
```

なんかすごく怒られた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826192/67536010-8687-968e-907b-2da5cdfde6d7.png)

<br/>

node.jsのバージョンかな？
Firebase公式には18以上使えって書いてあるけど、うちのは、16…？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826192/f296feff-1a91-9af1-66b6-1ca3d50fb98c.png)

## node.jsのバージョン
とりあえず、バージョンを上げてみます。
```
npm install -g n
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826192/eb7eb4bf-096c-1312-9acd-ff8224e22cca.png)

いや、同じエラーで怒られた。
>npm ERR! request to https://registry.npmjs.org/n failed, reason: connect ENETUNREACH 104.16.25.34:443

そもそも、環境起因なのかな。

<br/>

困ったときのStackOverflow先生に相談すると、
ip6優先だからだよってことだったので、
環境変数を追加っと。
```
export NODE_OPTIONS="--dns-result-order=ipv4first"
```

ダメだー、同じエラーしか出ない。
ちょっと一回nodejsをアンインストールして、仕切りなおそう。
```
sudo dnf erase nodejs
```

全部消えたっぽいので、
次はnvmを使って再度インストールしていきます。

## nvmを使ったインストール

curlコマンドでシェルを取得して、たたきます。
```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
cd .nvm
. nvm.sh
```

<br/>

念のため、nvmコマンドで確認し、NVMが返ってくることを確認。
```
command -v nvm
```

<br/>

では、安定版をインストールします。
```
nvm install --lts
```

<br/>

おぉ、22がインストールされています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3826192/dda44f6d-4209-f412-c5dd-9cd7e495bff9.png)

<br/>

今日はここまで。続きは別の日に。

<br/>

参考にしたサイト(ありがとうございました)
https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script
https://qiita.com/ffggss/items/94f1c4c5d311db2ec71a
LeetCodeを1日1題解いてみる (day38)

37日目に取り組んだ問題はこちら！

# 197. Rising Temperature

https://leetcode.com/problems/rising-temperature/?lang=pythondata

## 問題文
Table: `Weather`
```
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| id            | int     |
| recordDate    | date    |
| temperature   | int     |
+---------------+---------+
```
id is the column with unique values for this table.
There are no different rows with the same recordDate.
This table contains information about the temperature on a certain day.
 

Write a solution to find all dates' id with higher temperatures compared to its previous dates (yesterday).

Return the result table in any order.

## 僕の回答 (失敗作)
```py
import pandas as pd

def rising_temperature(weather: pd.DataFrame) -> pd.DataFrame:
    weather.sort_values(by="recordDate", inplace=True)
    weather["previous"] = weather["temperature"].shift(1)
    result = weather[weather["temperature"] > weather["previous"]]
    return result[["id"]].rename(columns={"id":"Id"})
```
これだと、以下のような日にちが連続でない場合に対応できていなかった。
```
Weather =
| id | recordDate | temperature |
| -- | ---------- | ----------- |
| 1  | 2000-12-14 | 3           |
| 2  | 2000-12-16 | 5           |
```

## 回答例

```py
import pandas as pd

def rising_temperature(weather: pd.DataFrame) -> pd.DataFrame:
    weather_shifted = weather.copy()
    weather_shifted["recordDate"] = pd.to_datetime(weather_shifted["recordDate"]) + pd.to_timedelta(1, unit="D")
    merged = pd.merge(weather, weather_shifted, on="recordDate", suffixes=("", "_prev"))
    result = merged[merged["temperature"] > merged["temperature_prev"]]
    return result[["id"]].rename(columns={"id": "Id"})

```

＃より良い解答例
```py
import pandas as pd

def rising_temperature(weather: pd.DataFrame) -> pd.DataFrame:
    weather.sort_values(by="recordDate",inplace=True)
    return weather.loc[(weather.temperature.diff()>0) & (weather.recordDate.diff().dt.days==1)][['id']]
```

## 学んだこと
- `diff()`
`weather.temperature.diff() > 0`で１つ上の行の気温との差を調べている。
`weather.recordDate.diff().dt.days == 1`で１つ上の行の日付との差が１日かどうか調べている。
- `weather["temperature"].shift(1)`
`temperature`の１つ上の行の値を取得する
- `weather.sort_values(by="recordDate",inplace=True)`

| パラメータ   | 説明 |
|:-----------|:-------|
| by | ソートする列名または列名のリスト。|
| axis | 0: 行ごとにソート（デフォルト）、1: 列ごとにソート |
| ascending |	True: 昇順（デフォルト）、False: 降順 |
| inplace |	True: 元の DataFrame を変更、False: 新しい DataFrame を返す |

- `pd.to_datetime(weather_shifted["recordDate"])`
`recordDate`列を`datetime`型に変換する
- `+ pd.to_timedelta(1, unit="D")`
１日を加える
`unit`には単位を指定する
一例↓ (大文字,小文字どちらでもいけるものといけないものがある)

| 値 | "s" | "m" | "h" | "D" | "W" | "M" |
| ---|:----:|:------:|:-----:|:----:|:-----:|:---:|
|単位| 秒| 分| 時間| 日| 週| 月|

## コメント
`shift()`や`diff`などのこんな操作があったらいいなーって思ったものがちゃんと用意されていることに感動しました。

## 次の問題はこちら!
https://qiita.com/h_y_s_d/items/73965f9ae70da4d58a36
R6元旦に起きた能登半島地震と11/26に起きた石川県西方沖に関連する話？

# 前置き
「今年ってほんとに最悪なことしか起きないよなぁ〜」と皆さんは思ったことないでしょうか？いや、思ったことありますよね？（圧）
元旦に石川県能登半島地震が起きたり、飛行機追突したり、神奈川県西部で5-とか起きたり、もうわんさか出てきますよ、、、
めっちゃ大変ですよねぇ〜色々と。
うちも中学生なんで期末やらなんやらと次々と予定が出き、大変です。
（前置き長くなってスマソ）
# 本題
### さてさて、ここからが本題ですよ？
つい最近に石川県西方沖で最大震度5-のでかい地震がありましたね。長周期地震動階級2でもう定期になってきた深さ10kmという浅い震源の深さ。確か元旦に起きた地震も浅かったですね。
んで、私は気づいちゃったんですよ。
元旦の時も今回の時もEEWで新島・神津島で誤報が発生したことを。
何故か前回も今回も同じ震源で誤報が発生してるんですよ。
今回はこいつ何故発生したんかと、めっちゃ簡潔にまとめようと思いまする。
# まとめ（？）
### 思ったことはもう気象庁の装置のバグとしか考えられませんよなぁ。
はい、ただそれだけです。
多分アルゴリズムかなんかが石川県ででけぇが発生した時に新島(ryでも発生するようになっちゃてるとか？まぁ自分はまだ中学生なんでこのぐらいしかわかりませんけど、しかもこれ気象庁の能登半島地震のEEW履歴見てもないし、報道もされてないというね。
# 終わりに
こんな馬鹿の考えたことを見てくださりありがとうございました。
多分主はWeeeeeeeと声をあげて大喜びしてるでしょうね。
では以上です。
crafty controllerを利用したminecraft 1.12.2forgeサーバーを立てるときの注意点

# 本記事が役に立つと思われる方
- dockerを利用してcrafty controllerを導入した人
- その中で1.12.2のforgeサーバーを立てたい人
- その中でもlinux経験が浅い人

要するに私と同じ境遇の方です。同じことで悩む方を減らしたいなと思い、初めてqiitaに記事を書いてます。
# crafty controllerのpanelへの入り方
https://docs.craftycontrol.com/pages/getting-started/installation/docker/

これを見て導入した方は、おそらくpanelを開くところまではたどり着いたと思います。でも、panelにアクセスした後に要求されるpasswordがわからない、という状況になると思います。私はこれで１時間悩みました。
通常の方法でcrafty controllerをインストールすれば、公式ドキュメントにある通りのディレクトリにアクセスすればよいのですが、dockerで導入した場合どこにpasswordが描かれたファイルがあるかわかりません。dockerで導入した場合、まずclafty controllerのdocker containerに入り、その中にある設定ファイルからパスワードを探し出す必要があります。
コンテナへの入り方:
```
docker exec -it crafty_container bash
```
これを実行すると、コンテナの中に入れます。
コンテナの中に入ったら、次にこう書いて実行します:
```
cat ./app/config/default-creds.txt
```
すると、
```
{
    "username": "admin",
    "password": "パスワード(環境によって違う)",
    "info": "This is NOT where you change your password. This file is only a means to give you a default password."
}
```
と出力されます。この"username"と"password"がパネルのusernameとpasswordになります。
無事にログイン出来たらパスワードを覚えやすいものに変えておきましょう。
# javaのバージョンについて
公式ドキュメントにも記載がありますが、ver1.12.2のサーバーはjava8でないと動きません。気を付けてください。
# 公式ドキュメントのforge導入法は1.12.2では通用しない
公式ドキュメントのforge導入についての記載は、ver1.12.2より後のforge導入を前提に書かれているようで、ver1.12.2のforgeを導入するときにこれを参考にすると、どうしてもエラーが発生してしまいます。
私はこれに１日ハマりました。
ひとまず記載されているStep3、zipのインポートまで終わらせてください。インポートしたら、サーバー管理画面のconfigを開いてください。
まず、Server Execution Commandの部分を書き換えます。
```
java -jar (メモリ量の設定) libraries/なんとかかんとか
```
となっているはずです。筆者の艦橋では確かそうでした。
ここの、libraries~の部分を書き換えます。1.12.2のforgeサーバーは、実行ファイルがサーバーファイル直下のforge-1.12.2-{forgeバージョン}.jarに存在しているためです。
書き換えるとこう:
```
java -jar (メモリ量の設定) forge-1.12.2-{forgeバージョン}.jar -nogui
```
そして、上にも書いたようにver1.12.2はjava8にのみ対応しているので、Override current Java Versionのところをのjava8っぽいのを選んでください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955905/5554de6a-d7ce-55e6-3162-43fcc3fb38ea.png)
(筆者はraspberryPiで鯖立ててるのでarm64になってます)
これで一回save。
最終的に、こんな感じになっていればいいです（これは筆者の環境での一例）
```
"/usr/lib/jvm/java-8-openjdk-arm64/jre/bin/java" -Xms4096M -Xmx7168M -jar forge-1.12.2-14.23.5.2859.jar nogui
```
最後に、上のほうにあるServer Executableも書き換えておきましょう。
forge-1.12.2-{forgeバージョン}.jarにしておけばいいです。（これも筆者の環境での一例）
```
forge-1.12.2-14.23.5.2859.jar
```
これで多分設定終わり。
# modの入れ方
サーバーが無事に起動できると、forgeがmodsファイルを作ってくれます。その中にjarを突っ込めばmodが導入できるわけですが、さて、dockerコンテナの中にあるmodsファイルにどうやってアクセスしよう？
私は考えました。panelのパスワードを探しに行ったときみたいにコマンドラインでアクセスすればいいと。
実際にやってみました。できました。でもめんどくさいです。modファイルなんて数十個あるのに全部やるのは大変。どうしようと考えていました。
サーバー管理画面のfilesタブで、なんとなく右クリックをしたその時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955905/319a2890-7596-1b2c-bbc0-baabc193ffb2.png)
uploadってあるじゃないか！！！！！！
はい。modsフォルダを右クリックしてuploadを選択、お使いのPCからmodsファイルをアップロードすれば終わりです。簡単ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955905/189933d6-4d6a-77c6-d768-d17c80ffed88.png)

# 終わりに
初めてのqiita記事でいきなりニッチなことを描いてしまいましたが、一人でもこの記事が参考になる方がいたらうれしいです。
【Unity6】WebGLでC#のマルチスレッドはまだサポートしてない

# 概要
Unity6でWebGL周りの機能が増えてきました
その中にこんなものがあります

> 私たちはまた、C と C++ のマルチスレッドもミックスし、ブラウザ内でのネイティブコードのパフォーマンスをさらに向上させる可能性を広げています。

https://unity.com/ja/blog/unity-6-features-announcement

てっきり自分はC#で書いたものも、うまいことC++周りに変換されてマルチスレッドが使えると思ってたけど違った

# 実験
こんな感じのマルチスレッドをテストするスクリプトを作ってみた
```csharp
using System.Threading;
using UnityEngine;
using TMPro;

public class ThreadTest : MonoBehaviour
{
    private int _count = 0;
    [SerializeField] private TMP_Text text;
    Thread thread;

    void Start()
    {
        thread = new Thread(() =>
        {
            while (_count < 1000)
            {
                Debug.Log("Thread: " + _count);
                _count++;
                Thread.Sleep(1000);
            }
        });
        thread.Start();
    }

    void Update()
    {
        text.text = "Count: " + _count;
    }

    void OnDestory()
    {
        thread.Abort();
    }
}
```

エディタやMacビルドだとちゃんとカウントアップしていく

![スクリーンショット 2024-12-09 0.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/2b60a848-1e49-402f-c0c0-be10a516faf7.png)

Unity6とUnity2022.3.54でWebGLビルドしてみたがカウントアップしない
![スクリーンショット 2024-12-09 0.00.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/0f89467d-9317-713b-0e4d-8c7e071aa121.png)

(ビルド時にPlayer Settingsの`Enable Native C/C++ Multithreading`をtrueにしている)
![スクリーンショット 2024-12-09 0.02.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/784fc04c-bfe6-9183-6374-ca081dc46c91.png)

やはりマルチスレッドは機能しないようだ

よく見るとツールチップにも書いてる
![スクリーンショット 2024-12-09 0.03.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/92479138-fed0-b850-45ae-69303b46b715.png)

>有効にすると、ネイティブ Unity C/C++ エンジン コードは WebAssembly/SharedArrayBuffer マルチスレッド (実験的) をターゲットにします。これにより、WebAssembly 言語標準のさらなる進歩が必要となるため、C# コードのマルチスレッドは有効になりません。このオプションを有効にすると、WebAssembly 2023 のサポートが含まれます。(推奨: 無効。この機能は、将来の Web 機能の評価に関心のある上級ユーザー向けに提供されています)

なるほど。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer

SharedArrayBufferとは、スレッド間で値を共有するための機能らしい

いつかC#のマルチスレッドが対応されることを祈ります
Docusaurus の scaffold で作成した Project で Blog 機能を廃止し docs 機能のみ使用するように変更する


## はじめに

Docusaurus の Project を簡単に始める方法として scaffold を使用する方法が推奨されています。
Scaffold で作成した Project には Blog 機能やトップページ等多くの機能が組み込まれています。

Docusaurus を単にドキュメント管理のために使用したい場合は `docs` 以外の機能を廃止したほうがスッキリするのでドキュメント管理のためだけに使用する方法を記載しておきます。

## scaffold 直後の構成

`npx create-docusaurus@latest my-website classic` 等で作成した直後の Project 構成は以下のようになっています。

```sh
> tree -L 2 -I node_modules/
.
├── README.md
├── blog
│   ├── 2019-05-28-first-blog-post.md
│   ├── 2019-05-29-long-blog-post.md
│   ├── 2021-08-01-mdx-blog-post.mdx
│   ├── 2021-08-26-welcome
│   ├── authors.yml
│   └── tags.yml
├── docs
│   ├── intro.md
│   ├── tutorial-basics
│   └── tutorial-extras
├── docusaurus.config.ts
├── package-lock.json
├── package.json
├── sidebars.ts
├── src
│   ├── components
│   ├── css
│   └── pages
├── static
│   └── img
└── tsconfig.json
```

## `blog` ディレクトリの削除 及び 設定の変更

不要となる `blog` ディレクトリを削除'します。

```sh
rm -rf blog
```

及び `src/pages/index.tsx` を削除します。

```sh
rm src/pages/index.tsx
```

`docusaurus.config.ts` 内の `blog` に関する設定を削除するとともに、 `docs` に `routeBasePath: "/",` を追加します。

```diff_typescript:docusaurus.config.ts
const config: Config = {
  // 他設定 ...
  presets: [
    [
      'classic',
      {
        docs: {
+         routeBasePath: "/",
          sidebarPath: './sidebars.ts',
          // Please change this to your repo.
          // Remove this to remove the "edit this page" links.
          editUrl:
            'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
        },
-       blog: {
-         showReadingTime: true,
-         feedOptions: {
-           type: ['rss', 'atom'],
-           xslt: true,
-         },
-         // Please change this to your repo.
-         // Remove this to remove the "edit this page" links.
-         editUrl:
-           'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
-         // Useful options to enforce blogging best practices
-         onInlineTags: 'warn',
-         onInlineAuthors: 'warn',
-         onUntruncatedBlogPosts: 'warn',
-       },
        theme: {
          customCss: './src/css/custom.css',
        },
      } satisfies Preset.Options,
    ],
```

ここまで対応すれば `/` へアクセスした際に docs 以下のコンテンツが表示されるようになります。

## 追加オプション

### ヘッダーから Blog リンクの削除

必要に応じて ヘッダーから `/blog` へのリンクを削除します。

```diff_typescript:docusaurus.config.ts
const config: Config = {
  // 他設定 ...
  themeConfig: {
    // Replace with your project's social card
    image: 'img/docusaurus-social-card.jpg',
    navbar: {
      title: 'My Site',
      logo: {
        alt: 'My Site Logo',
        src: 'img/logo.svg',
      },
      items: [
        {
          type: 'docSidebar',
          sidebarId: 'tutorialSidebar',
          position: 'left',
          label: 'Tutorial',
        },
-       {to: '/blog', label: 'Blog', position: 'left'},
        {
          href: 'https://github.com/facebook/docusaurus',
          label: 'GitHub',
          position: 'right',
        },
      ],
    },
```

## Ref

https://docusaurus.io/docs/installation
ActiveStorageとS３の初心者まとめ

## はじめに
こんにちは、メダカです。今回は私のポートフォリオでAWSが提供しているサービスである「S3（Amazon Web Services）」を取り入れたいと思い調べた内容を共有いたします。

## ActiveStorageとS3について
S3を調べているとどうやら、ActiveStorageをまずは理解していないといけないっぽい。ということで、調べました。
#### ActiveStorage
公式には、「Active Storage を使用すると、Amazon S3、Google Cloud Storage、Microsoft Azure Storage などのクラウド ストレージ サービスにファイルをアップロードし、それらのファイルを Active Record オブジェクトに添付することができます。」とのことです。
なるほど、、、全く理解できませんでした。ということでもう少し調べてみると、分かってきました。
簡単に一言で言えば、railsに標準で装備されている「ファイル管理の仕組み」のことらしい。これがあることで、画像や動画、PDFなどのファイルをアップロードしたり表示ができる。
##### ActiveStorageの役割
###### ①ファイルのアップロード
ユーザーが画像や動画をアプリにアプロードできます。今回の私はこの機能を使用して、筋トレの自撮り動画を送るシステムを考えています。
###### ②外部ストレージとの連携
また難しい単語が出てきましたが、これはActiveStorageがローカル上のファイル保管庫だとしたら、外部ストレージはクラウドストレージ上（S３など）のファイル保管庫のことです。つまり、ローカルで容量などが足りない時などに外部ストレージと連携がすぐできる。今回はこちらも実践します。
###### ③ファイルのデータを保存（アタッチ）
ユーザーがファイルをアップロードした時に、ファイル本体は指定したストレージ（ローカルや外部）に保存されます。そして次にファイル情報がactive_storage_blobsに保存され、モデルとの紐付け情報（これがアタッチというらしい）がactive_storage_attachmentsに保存される。勝手にモデルとの紐付けをしてくれるのはすっごく便利ですね。

#### S3（Amazon Simple Storage Service）
AWSが提供しているオンラインストレージサービス。ユーザーの規模が多くなったときの利用負荷の増大に対応できることや、優れた可用性、セキュリティなどを提供しています。

## 手順
###### 用意しておくこと
以下の２つのアカウントを用意します。
・AWSアカウント
・IAMユーザー

#### S3バケット（S3におけるフォルダという認識）
まずはAWS CLIでバケットの作成をするので、インストールします。
```php:bash
brew install awscli
```
次にIAMユーザーの情報をもとにAWS CLIの設定をします。
```php:bash
aws configure
```
上記のコマンドを入力するとIAMユーザーのAccess Key IDやSecret access Keyなどが求められるので入力してください。
いよいよバケットの作成です。
```php:bash
aws s3 mb s3://バケット名
```
上記のコマンドでバケットの作成は完了です。
もし、パブリックアクセスの設定等が必要な場合はここで、コマンドを入力します。ここら辺はまだ理解が浅いところです。。。

#### Active Storageの設定
こちらは[Active Storage](https://railsguides.jp/active_storage_overview.html)のガイドを参考にしたところ簡単にできました。
```php:config/storage.yml
amazon:
    service: S3
    access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
    secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
    region: ap-northeast-1
    bucket: バケット名
```
コメントアウトされているところを外して修正すると良いです。

以上でActiveStorageとS3の設定が完了しました。

## 終わりに
なかなかこれらを暗記はできませんが、何度も使っているうちに覚えてくる日を願い、今日も勉強を進めていきます。ここまで閲覧いただき誠にありがとうございました。
レイアウトを維持したままLLMに外面的なデザインを生成させるUIコンポーネントライブラリを開発している話


この記事は [SecHack365 Advent Calendar 2024](https://qiita.com/advent-calendar/2024/sechack365) の 9 日目の記事です。

SecHack365'24 開発駆動コース仲山ゼミ トレーニーの [@newt239](https://x.com/newt239) です。有志トレーニー（&アシスタント）によるアドカレということで、今年度 SecHack365 で開発している UI コンポーネントライブラリ「Ginga UI」についての話をしようと思います。

## これはなに？

文章で説明するより見てもらったほうが早いと思うので、まずは以下のツイートをご覧ください。

https://x.com/newt239/status/1847925274207457716

私のポートフォリオサイト上に実装した「LLM に配色を生成させる機能」のデモ映像です。この機能は以下のページにアクセスすることで、誰でもサクッとお試しいただけます。

https://newt239.dev/

簡単にしくみを説明すると、ユーザーから入力されたキーワードをバックエンドに渡し、OpenAI の API へ、キーワードに合ったカラーコードを生成するよう指示を出しています。

以下はフロントエンドのリポジトリです。それぞれの Vue コンポーネントで CSS を確認すると、色を指定する箇所では CSS 変数を利用して指定していることが分かると思います。

https://github.com/newt239/newt239.dev

バックエンドとして稼働させている API サーバーは以下のリポジトリで、Hono で実装しています。`src/routes/ai/index.ts`が本機能に関わる部分で、Cloudflare D1 でリクエストを記録し、24 時間あたりのリクエスト回数に制限をかけています。プロンプトではユーザーからのキーワードに合う色を考え、与えた CSS 変数の値を HEX 形式で考えるように指示を出しています。レスポンスは OpenAI の Structured Output を利用し、期待するフォーマットをあらかじめリクエストに含めています。

https://github.com/newt239/api.newt239.dev

## Generative UI という考え方

生成 AI x UI というアプローチは最近の流行りですが、この文脈の話を探っているとよく「Generative UI」というキーワードを目にします。Vercel による 2023 年 10 月の記事「[**Announcing v0: Generative UI**](https://vercel.com/blog/announcing-v0-generative-ui)」では、Generative UI という用語を「フロントエンド開発のベストプラクティスと生成 AI の可能性の融合」と説明していますが、私個人的にはこの言葉はより広い意味を持つべきだと考えていて、「AI による UI への干渉」全般を指すもの、というくらいの括りで使うのがちょうどよいのではないかと思っています。

v0 は入力されたプロンプトに適した Web フロントエンドのコードを生成し、対話形式で改善していくことができるサービスですが、近年類似のサービスは増えており、2024 年 10 月に StackBlitz が発表した [Bolt.new](https://bolt.new/) や、同月末に Github が発表した [GitHub Spark](https://githubnext.com/projects/github-spark) など、大手が相次いでリリースを行っています。

## SecHack365 で作っているもの

上記したような実装は、開発者がどの部分でどの CSS 変数を使うか、いくつ変数を用意するか等を十分に吟味する必要があり、大規模なウェブサイトで取り入れるのは現実的ではありません。

Ginga UI はこれらの問題を考えることなく、AI によるテーマ生成を簡単に実装することができる UI コンポーネントライブラリを目指しています。

## Ginga UI が目指すもの

この UI コンポーネントライブラリが目指しているのは「**ユーザーに新たな体験を届ける**」という点です。

前述した v0 などのサービスは「開発者をサポートする」という点に主軸が置かれていますが、私はレイアウトなどの情報設計は AI に任せるべきではないと考えているため、このライブラリはそれらとはターゲットが異なります。

活用例として、長文投稿サイト等の UGC (User Generated Contents) が主となる Web サイトや、個人のブログサイトへの導入が考えられます。

文章のテイストや著者の嗜好に応じて、ページごとにデザインが異なる Web ページを表示することで、没入感の高い体験をユーザーが得られるはず、と考えています。

## 進捗

風呂敷を広げるだけ広げて夢物語を語っていますが実際はそう単純なものではなく、実用に足るものに至るまでまだいくつかの課題が残っています。

例として、「2, 3 色で表現することが難しいキーワードにどう対応するのか」という問題があります。「虹」というキーワードを視認性を損なわずに表現するのは困難です。また、「哲学」のような抽象的なキーワードが入力された場合、適切な表現方法を決めるのも難しい問題だと言えるでしょう。私個人としてはある程度「AI のランダム性」に任せたいという気持ちがあるため、あまりプロンプトを長くして縛るようなことはしたくないですが、コントラストの確保など、視認性に関わる部分についてはある程度制限をかける必要はあると考えています。これについては、例えばコントラストを計算した結果が一定値を下回った場合再生成させる、といった方法が考えられます。

他にもいろいろ考えていることはあるんですが、自分の中で結論が出ていないものも多いというのと、まだ修了まで時間があるので、この記事ではここまでにしておきます。3 月上旬に SecHack365 の成果発表会があり、私以外にも面白いものを作っているトレーニーが大勢いるので、ぜひお越しただければと思います。

## むすびにかえて

現在すでに npm レジストリからインストールすることが可能ですが、まだ実用に足る段階には達していないため、導入は今しばらくお待ちください。

以下のリポジトリで開発を行っているので、興味を持っていただけた方がいましたらぜひ star をポチっとつけてもらえると喜びます。

https://github.com/newt239/ginga-ui
9日目: RangeSetを実装する

[競プロ用ライブラリを作る Advent Calendar 2024](https://qiita.com/advent-calendar/2024/yukkku-ribitol)の9日目です.

https://qiita.com/advent-calendar/2024/yukkku-ribitol

# RangeSet って?

競プロをやっていると時々, 集合をいくつかの区間の組み合わせで表現したくなる時があります.
ということで集合をいくつかの区間の組み合わせで表現するデータ構造を今RangeSetと名付けました. これを実装します.

# 仕組み

色々考えた結果,「区間の境界を昇順に並べた配列$a = [a_1,a_2,...,a_N]$」と「無限小を含むフラグ$f$(0 or 1)」の組でやるのが一番簡潔そうだという結論に至りました. この組が表す集合を, 以下$S(a, f)$と書くことにします.

$S(a, f)$は「$a_i\le x$になる$a_i$の個数$+f$が奇数のとき, かつそのときに限り$x\in S(a, f)$」という集合です. 表現を変えると
- $f = 0$ のとき, $S(a, f) = \left[a_1,a_2\right)\cup\left[a_3,a_4\right)\cup\left[a_5,a_6\right)\cup\cdots$
- $f = 1$ のとき, $S(a, f) = \left(-\infty,a_1\right)\cup\left[a_2,a_3\right)\cup\left[a_4,a_5\right)\cup\cdots$

という感じです. どちらも$a$が区間の境界を昇順に並べたようになってますね.
それと, 区間に$a$の要素を2つずつ割り当てると偶奇によっては1余りますが, そういう場合は$\cdots\cup\left[a_{N-2},a_{N-1}\right)\cup\left[a_N,\infty\right)$みたいな感じの集合を表しているとします.

この集合の演算ですが, まず$S(a, 0)$と$S(a, 1)$は補集合になってるので, $f$を切り替えれば補集合が$O(1)$で求められます.

和集合, 積集合, 排他的和集合を実装します. 2つの集合と論理演算$\star$を使って$S(c, h) = \set{x: (x\in S(a, f)) \star (x\in S(b, g))}$という集合を新しく作りましょう. 以下のようにします.

- $h = f \star g$になる
- $c$を空の配列で初期化する
- $a, b$の値を小さいほうから順に出して(以下, その値を$x$), 順に次のことをする
  - $x\in a$なら$f$を反転する
  - $x\in b$なら$g$を反転する
  - 上の2つの操作を行った結果$f\star g$の値が切り替わったなら, $c$に$x$を追加する

これを共通化してしまえばあとは楽です.
Rustではイテレータよりも高階関数で実装した方が簡単なのでそうしましょう.

# 実装

- [`rangeset.rs`](https://github.com/Yukkku/ribitol/blob/main/src/rangeset.rs)

上で書いたことをそのまま実装しただけです.
Rustはコピーを行わずに「配列の値を小さいほうから順に出す」を実装するのがだいぶ重いです. 頑張りましょう.

# まとめ

いかがでしたか?

明日は乱択なやつを実装します.
バケツソートの実装

この記事は「[大分高専 Advent Calendar 2024](https://adventar.org/calendars/10845 "大分高専 Advent Calendar 2024")」9日目の記事です．

## はじめに
絶賛テスト期間中の高専生，S2108です．アルゴリズムのテストにバケットソートの穴埋め問題が出てきたので，復習の意味も込めてC言語で実装してみました．バケツソートとも呼ぶらしいです．どんなソートかの説明は省略します．~~勝手に調べてください．~~
初記事です！

### C言語での実装

```C:main.c
#include<stdio.h>
#define MAX 10

void bucket_sort(int number[], int num_of_item){
  int i,buckets[MAX];

  for (i = 0; i < MAX; i++)
  { // バケツを用意する
    buckets[i] = 0;
  }

  for (i = 0; i < num_of_item; i++)
  { // 元のデータをバケツに入れる
    buckets[number[i]] = number[i];
  }

  int j=0;
  for (i = 0; i < MAX; i++)
  { // バケツから元の配列に戻す
    if (0 < buckets[i]) number[j++] = buckets[i];
  }
  
}
int main(void) {
  int numbers[] = {3,5,6,2,7,1};
  int length = sizeof(numbers)/sizeof(numbers[0]);
  // length : 配列の長さ
  
  printf("before : ");
  for (int i = 0; i < length; i++) printf("%d ",numbers[i]);
  printf("\n");
  
  bucket_sort(numbers,length);

  printf("after : ");
  for (int i = 0; i < length; i++) printf("%d ",numbers[i]);

  printf("\n");
  return 0;
}
```
bucket_sort関数には，配列と配列の要素数を渡す．

### 出力
```Bash
$ gcc main.c 
$ ./a.out 
before : 3 5 6 2 7 1 
after : 1 2 3 5 6 7 
```

## 終わりに
以上バケツソートの実装でした．すごく直感的でわかりやすいソートで，データの個数が少なくて，値が被らない保証がある時には役に立ちそうだなと思いました．
残りのテスト頑張るぞー！


### おまけ 〜Goでの実装〜
最近Go言語に興味があるので，Goでも実装してみました．C言語に似てるらしい．

```go:main.go
package main

import (
    "fmt"
)
var MAX = 10

func bucket_sort(number []int) []int{
	var num_of_item = len(number)
	var buckets = make([]int,MAX)
	//make(型，大きさ)

	for i := 0; i < MAX; i++ {
		// バケツを用意する
		buckets[i] = 0
	}
	
	for i := 0; i < num_of_item; i++{
		// 元のデータをバケツに入れる
		buckets[number[i]] = number[i]
	}
  
	var j = 0
	for i := 0; i < MAX; i++ {
		if 0 < buckets[i]{
			number[j] = buckets[i]
			j++
		}
	}
	return number
}
func main() {
	var numbers = []int{3,5,6,2,7,1}

	fmt.Printf("before : ")
	for _, v := range numbers {
		fmt.Printf("%d,",v)
	}
	fmt.Printf("\n")

	numbers = bucket_sort(numbers)
	fmt.Printf("after : ")
	for _, v := range numbers {
		fmt.Printf("%d,",v)
	}
	fmt.Printf("\n")
}
```

#### 出力
```Bash
$ go run main.go 
before : 3,5,6,2,7,1,
after : 1,2,3,5,6,7,
```

C言語に似てるって言われてるけど，変数の宣言とか若干違ってややこしい．勉強します..
【イベント運営】ワークショップ開催の時に気をつけていること3選！！


みなさんこんにちは。
デジタル創作サークルUniProjectの運営メンバーの一人、あかつきゆいとと言います。

今回はワークショップを開く時になるべく気をつけていることをつらつらと書いていきたいと思います。

## はじめに

なんで私がワークショップを開くかについて書いておこうかと...

私は先も書いたようにサークルを運営しています。
そこでよく目にするのが、**プログラミングの始め方がわからない**といった声や、**新しい技術にチャレンジしてみたいけど、ハードルが高すぎる**という声です。

もちろん、DiscordのVCなどで教えたりもしますが、個別で教えるのにも限界があります。
そこで、ワークショップをひらけば、多くの人に一度に、チャレンジする機会を与えられる。
そう思ってワークショップを時間がある時に細々と開いています。

## 1つ目「スライドはわかりやすく！！」

皆さん、
「口頭で言うんだから、スライドは適当でもいいんじゃない？」
そう思ってはいませんか？

そうではありません。
参加者は、**スライドが後で見返せると非常にありがたいのです**。

どうしてもついていけないところも出てきます。
その時に、スライドが見返せると追いつくことができるのはもちろん、終了した後に自分でスライドを見ながら進めることもできます。

余談ですが、私はスライドをGoogleSlideで作っていたり、MarpというMarkdownからいい感じに作ってくれる非WYSIWYGのツールで作っていたりします。
MarpはサークルのWikiシステム、Growiでもサポートされていて、サークルWikiで簡単に共有できるので重宝しています。

## 2つ目「はしょらない」

やっぱね、省略しちゃうんですよ、環境構築とか。
初心者さんはそこも含めてわからないんですよね。
なので、**なるべく細かく書く**。

例えば、「あとはビルドするだけです」と言った時に、経験者にはそれで伝わりますが、初心者は慣れていないので、最初に説明していても、もう一度ビルドする手順を大まかに書いたスライドを挟むなどしなければなりません。

## 3つ目「簡単なものから」

ここが一番難しいと言っても過言ではない...**話題選び**です。

初心者向けに教える時、私は以下の基準に照らし合わせて考えます。

- 長くとも3時間以内に終わるか
- ライブラリを多用していないか
- オブジェクト指向がある場合、それ特有の動作をしていないか

少なくともこの3つは必ずチェックします。

長ければ飽きられてしまいますし、ライブラリが多いと初心者は全て覚えようとしたりするのでこれまたしんどい。
オブジェクト指向型なんぞ、1年やってる人でもわからない人が多いくらいなので、安易に踏み込む内容ではないですね。

## まとめ

ワークショップって結構難しいもんですよね。
ただ、自分の知っていることを教えて、自分の好きなことを好きになってくれるかもと考えると、それまたいいものです。

皆さんもこれを読んで、ワークショップ運営、初めてみてはいかがでしょう？
データベース基礎理論の結合演算

## はじめに

今日は、リレーショナルデータベースでよく使われる「結合演算」についてまとめます。
結合演算には、θ結合、等結合、自然結合、外部結合など様々な種類があります。基本的な考え方としては、まず2つの関係（テーブル）の直積を取り、その中から条件を満たすタプル（行）を選択し、不要な列を射影していくことで目的の結果を得ます。

## 本文

ここでは、サンプルとして以下の2つのテーブルRとSを用います。

Rテーブル
| A | B  |
|---|----|
| 1 | X  |
| 2 | Y  |
| 3 | Z  |

Sテーブル
| A | C  |
|---|----|
| 2 | Q  |
| 3 | R  |
| 4 | S  |

### θ結合

θ結合は、直積から2つの属性に対し、`<, >, <=, >=, =, <>（等しくない）`などの比較演算子を用いて選択したタプル集合を得る結合です。R.A > S.A を条件としたθ結合の場合、RとSの直積からR.A > S.Aを満たす行のみ取り出します。

SQL
```sql
SELECT * FROM R INNER JOIN S ON R.A > S.A;
```

R×Sは以下のような直積になります（Rが3行、Sが3行なので計9行）

R.A|R.B|S.A|S.C
---|---|---|---
1 | X | 2 | Q
1 | X | 3 | R
1 | X | 4 | S
2 | Y | 2 | Q
2 | Y | 3 | R
2 | Y | 4 | S
3 | Z | 2 | Q
3 | Z | 3 | R
3 | Z | 4 | S

ここからR.A > S.Aを満たす行を抽出すると、`3 > 2` が真なので `(3,Z,2,Q)` のみが選ばれます。

結果
|R.A|R.B|S.A|S.C|
|---|---|---|---|
|3  |Z  |2  |Q  |


### 等結合 (Equi-join)

θ結合で比較演算子が"="の場合が等結合です。

SQL
```sql
SELECT * FROM R INNER JOIN S ON R.A = S.A;
```

結果
R.A = S.Aを満たすのはA=2とA=3のペア
|R.A|R.B|S.A|S.C|
|---|---|---|---|
|2  |Y  |2  |Q  |
|3  |Z  |3  |R  |


### 自然結合 (Natural join)

自然結合は等結合から、2つの関係の共通属性を1つ除いて射影演算を行ったものです。
R.AとS.Aが等しい行を結合し、A列を1つにまとめます。

SQL
```sql
SELECT * FROM R, S ON R.A ＝ S.A
-- or
SELECT * FROM R NATURAL JOIN S; -- 一部のDBでNATURAL JOINが使用可能
```

結果
等結合結果から共通属性Aを1つにまとめる
|A |B |C |
|--|--|--|
|2 |Y |Q |
|3 |Z |R |

### 外部結合（Outer join）

内部結合（INNER JOIN）は対応する行が両方に存在する場合のみ取り出しますが、外部結合（OUTER JOIN）は、一方のテーブルに該当行がなくてもその側の行は残し、相手側に値がなければNULLを補います。

#### 左外部結合

左外部結合では、左側（FROM句で左に書いた）のテーブルRは全行保持し、Sに一致がなければNULLを補います。

SQL
```sql
SELECT R.A, R.B, S.C FROM R LEFT OUTER JOIN S ON R.A = S.A;
```

結果
RにA=1があるがSにA=1はないため、その行はNULLを補います。
|A |B |C   |
|--|--|----|
|1 |X |NULL|
|2 |Y |Q   |
|3 |Z |R   |

#### 右外部結合

右外部結合は右側のテーブルSを基準に全行保持し、Rで一致しない行にはNULLを補います。

SQL
```sql
SELECT R.A, R.B, S.C FROM R RIGHT OUTER JOIN S ON R.A = S.A;
```

結果
SにA=4があるがRにA=4はないため、S側は保持してR側にNULLを補います。
|A   |B   |C  |
|----|----|---|
|2   |Y   |Q  |
|3   |Z   |R  |
|NULL|NULL|S  |


#### 完全外部結合

共通属性に関し、どちらかの列に存在する行を全て取り出す結合です。

SQL
```sql
SELECT R.A, R.B, S.C FROM R FULL OUTER JOIN S ON R.A = S.A;
```

結果
|A   |B   |C   |
|----|----|----|
|1   |X   |NULL|
|2   |Y   |Q   |
|3   |Z   |R   |
|NULL|NULL|S   |

## まとめ

結合演算は、複数の関係を関連付け、必要な情報を1つの結果セットとして取得するための基本手法です。さまざまなニーズに応じて使い分けることができます。明日はデータベース設計についてまとめます！
脱イライラ！FormsをEdgeで開くQRコードを作成する

[KDDI エンジニア＆デザイナー Advent Calendar 2024](https://qiita.com/advent-calendar/2024/kddi)の14日目の記事を書いています。こんなに記事投稿するつもりなかったのにどんどんネタが出てきているため投稿します。

# FormsのQRコード、Edgeで開きたい！
M365利用している一部の企業のiOS民あるあるだと思うのですが、研修やらイベントやらで提示されるFormsのアンケートをEdgeで開きたいのに規定のSafariで開いてしまってイライラすることはありませんでしょうか？認証がSafariだと通っておらずEdgeだといけるからいちいちURLコピペしてる…みたいな。

まぁ「設定」で規定のアプリにすればいいだけなんですが、そんな設定していない人向けにFormsを展開することもあると思うので。。。やってみました。

# URLスキームをいじってQRコードからEdgeで開くようにしよう

## URLスキームとは？

URLスキームとはリソースにアクセスするためのプロトコルや方法を指定する部分です。
いつもはhttps://~とかいてあるあそこです。
ちなみに、ここをmailto:でURL指定しておくとメールクライアントが開いたりします。
今回のように開きたいアプリを指定することも可能です。

今回はここをmicrosoft-edge:に変えてみましょう

```
microsoft-edge:forms.office.com
```
## QRコードを作成してみよう

私はいつもパブリックにしてもいいURLであればアドビの以下サービスを使っています。
会員登録せずに利用できます。

https://www.adobe.com/jp/express/feature/image/qr-code-generator

これで、QRコードを作成してみましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/01cd9105-f741-59b2-a8db-fac76ae0548c.png)


きちんとEdgeで開けることが確認できますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/7e73e0e3-ba93-289c-3cf7-efddd520b22f.png)


もし社内のURL等を作成する場合は、念のため安心安全のExcel等を利用して作りましょう。

▼やりかたはこちらから

https://qiita.com/ponponmikankan/items/5748ae303effc3edf54a
【React】マウスポインタが要素に入った時に押下されているボタンの判定方法

mouseenterイベントが発生した際に押下されていたボタンを判定するには`MouseEvent.buttons`を使用します。以下の場合には主ボタンが押下されていたか判定できます。

```tsx
import { useCallback, useEffect, useRef, useState } from 'react'
import { Button } from '@/components/buttons/button'

export function Sample({ children }: { children: React.ReactNode }) {
  const handleMouseEnter = (ev: React.MouseEvent<HTMLDivElement>) => {
    if (ev.buttons === 1) {
      // 主ボタンが押下されていた場合の処理
    }
  }

  return (
    <div onMouseEnter={handleMouseEnter}>
      {children}
    </div>
  )
}

```

各ボタンの値は以下のとおりです。

| 値 | ボタン |
| --- | --- |
| 0 | ボタンが押されていない、または初期化されていない |
| 1 | 主ボタン (通常は左ボタン) |
| 2 | 副ボタン (通常は右ボタン) |
| 4 | 補助ボタン (通常はマウスホイールボタンまたは中央ボタン) |
| 8 | 第四ボタン (通常は「ブラウザーで戻る」ボタン) |
| 16 | 第五ボタン (通常は「ブラウザーで進む」ボタン) |

複数ボタン押下されている場合には値が合計されます。

https://developer.mozilla.org/ja/docs/Web/API/MouseEvent/buttons