OmniAICreator/Qiita-1.07M huggingface dataset:
テッセレーションとLOD：3Dグラフィックスを滑らかに表現するための2つの技術

3Dグラフィックスの世界では、よりリアルで滑らかな表現を実現するために様々な技術が用いられています。その中でも、テッセレーションとLOD（Level of Detail）はオブジェクトの形状を動的に変化させることで、より自然な表現を実現する重要な技術です。

この記事では、テッセレーションとLODの違い、それぞれの仕組みを解説します。

## テッセレーションとLOD

### テッセレーションとは？

テッセレーションとは、簡単に言うと、3Dモデルのポリゴン数をリアルタイムで増減させる技術です。

* **低ポリゴンモデルの活用:** 3Dモデルは、多くのポリゴンで構成されています。しかし、全てのオブジェクトを常に高ポリゴンで表示すると、グラフィック処理の負荷が非常に高くなり、リアルタイムな描画が困難になります。
* **視点や距離に応じたポリゴン数の調整:** テッセレーションでは、視点から近いオブジェクトや、細かな形状表現が必要な部分のポリゴン数を増やし、遠方のオブジェクトや、それほど詳細な表現が必要ない部分のポリゴン数を減らすことで、全体的なグラフィック品質を維持しつつ、処理負荷を軽減します。
* **滑らかな曲面表現:** 特に、曲面を持つオブジェクトの場合、テッセレーションによってポリゴン数を増やすことで、より滑らかで自然な曲面表現が可能になります。

### LOD（Level of Detail）とは？

LODとは、オブジェクトの形状を複数のレベルで用意し、視点からの距離や重要度に応じて、表示するレベルを切り替える技術です。

* **複数の詳細レベルのモデル:** LODでは、同じオブジェクトに対して、ポリゴン数が異なる複数のモデルを用意します。
* **視点からの距離に応じたモデルの切り替え:** 視点から遠いオブジェクトは、ポリゴン数の少ない低詳細レベルのモデルを表示し、視点から近いオブジェクトは、ポリゴン数の多い高詳細レベルのモデルを表示することで、全体的なグラフィック品質を維持しつつ、処理負荷を軽減します。
* **オブジェクトの重要度に応じたモデルの切り替え:** 例えば、プレイヤーキャラクターは常に高詳細レベルのモデルを表示し、遠方の背景オブジェクトは低詳細レベルのモデルを表示するといった、オブジェクトの重要度に応じた切り替えも可能です。

### テッセレーションとLODの違い

| 特徴 | テッセレーション | LOD |
|---|---|---|
| ポリゴン数の変化 | リアルタイムで増減 | 複数のモデルを切り替え |
| 詳細レベル | 局所的な詳細レベルの調整 | オブジェクト全体の詳細レベルの調整 |
| 目的 | 滑らかな曲面表現、細かい形状表現 | 処理負荷の軽減、遠方オブジェクトの簡略化 |




## メリット・デメリット

### テッセレーション

**メリット**

* **滑らかな曲面表現:** ポリゴン数を動的に変化させることで、より自然な曲面を表現できます。
* **細部の表現:** オブジェクトの細かなディテールを表現し、高品質なビジュアルを実現できます。
* **柔軟性:** リアルタイムでポリゴン数を調整できるため、様々なシーンに対応できます。

**デメリット**

* **計算負荷:** ポリゴン数を増やすと、GPUへの負荷が増大し、フレームレートが低下する可能性があります。
* **実装の複雑さ:** テッセレーションを実装するためには、シェーダープログラミングなどの高度な知識が必要となる場合があります。
* **品質低下:** テッセレーションの過度な使用は、ノイズやアーティファクトの原因となる可能性があります。

### LOD（Level of Detail）

**メリット**

* **処理負荷の軽減:** 遠方のオブジェクトや重要度の低いオブジェクトを簡略化することで、GPUへの負荷を軽減できます。
* **フレームレートの向上:** 処理負荷の軽減により、フレームレートを向上させ、より滑らかな動きを実現できます。
* **視覚的な効果:** LODの切り替えを適切に行うことで、より自然な遠近感を表現できます。

**デメリット**

* **画質の低下:** LODの切り替えが視覚的に不自然になる可能性があります。
* **準備作業の増加:** 複数のLODモデルを作成する必要があるため、制作コストが増加する可能性があります。

## まとめと使い分け

* **テッセレーション**は、オブジェクトの細部表現や滑らかな曲面表現に優れていますが、計算負荷が高くなるというデメリットがあります。
* **LOD**は、処理負荷の軽減や遠近感の表現に優れていますが、画質の低下や準備作業の増加というデメリットがあります。

**どちらの技術を使うべきか**は、ゲームやアプリケーションの要求によって異なります。

* **高品質なビジュアルを重視する場合:** テッセレーションが有効です。ただし、GPUの性能に合わせて適切な設定を行う必要があります。
* **処理負荷を軽減し、滑らかな動きを実現したい場合:** LODが有効です。LODの切り替えを適切に行うことで、画質の低下を最小限に抑えることができます。
* **両方の技術を組み合わせる:** 多くの場合、テッセレーションとLODを組み合わせて使用することで、より良い結果を得ることができます。
JavaScriptでマウスカーソル位置の単語を取得する方法が難しかった

# これはなに？
ばにらJavaScriptにおいて、ページ全体に設定したEventListener内で、マウス位置の単語を取得する方法。

# 概略
JavaScriptで特定の文字列のクリックイベントやマウスオーバーイベントを取得するにはspanタグで囲うなどの方法が用いられるが、例えばUserScriptやBookmarkletで表示中のページにあるすべて特定の文字列にspanを設定することは難しい。たとえば、innerHTMLで単純置換を行うと、hrefやalt attributeに特定の文字列が設定されていれば、ページが崩壊してしまう。また、DOM操作を行うにしても、TextNodeから一部にspanタグを設定して、しかも前後のタグとの関係を処理することは困難である。そこで、この記事ではwindow.addEventListenerでページ全体に設定したイベント内で、マウスカーソルの位置にある単語(英語などのスペース区切りの言語に限る)を取得する方法を紹介する。

# コード

```javascript
document.addEventListener("mousemove", (event) => {
    // マウス座標を取得
    const x = event.clientX;
    const y = event.clientY;
    
    // 座標位置にあるDOM要素を取得
    const element = document.elementFromPoint(x, y);
    
    console.log(getWordFromElement(element, x, y));
});
function getWordFromElement(element, x, y) {
    // 変数の初期化
    const range = document.createRange();

    // エレメント内に複数のノードがある場合、文字列の含まれるTextNodeを探す。
    for (let i = 0; i < element.childNodes.length; i++){
        // 子要素を1つずつ見ていく
        let node = element.childNodes[i];

        // 子要素がテキストノードなら選択中の単語を確認
        if(node.nodeType == Node.TEXT_NODE){
            const text = node.textContent;
            // 正規表現で単語を検索
            const re =/[a-zA-Z0-9\-]+/g;
            let match;
            // 見つかった単語を1つずつ確認していく
            while((match = re.exec(text)) != null){
                // rangeに始まりに見つかった単語の1文字目の位置を記録
                range.setStart(node, match.index);
                // rangeの終わりに見つかった単語の最後の文字の位置を記録
                range.setEnd(node, match.index + match[0].length);
                
                // rangeのページ上での座標を取得
                const rects = range.getClientRects();
                // マウスカーソルの位置が見つかった単語の描画域の中にあるか判定
                for (let j = 0; j < rects.length; j++){
                    const rect = rects[j];
                    if(rect.left <= x && x <= rect.right &&
                        rect.top <= y && y <= rect.bottom
                    ){
                        // マウスカーソルの位置であれば、その単語を返す。
                        return match.toString();
                    }
                }   
            }
        } else {
            // TextNodeじゃなかったら子要素も探索
            word = getWordFromElement(node, x, y);
            if(word.length > 0){
                return word;
            }
        }
    }
    return "";
}
```
[Ubuntu / WSL / GLFW] Unable to locate package glfw の対策

# 症状

```bash
$ apt-get install glfw
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package glfw
```

# 対策

```bash
$ apt-get update
$ apt-get install libglfw3 libglfw3-dev
```

# 参考にした記事

https://github.com/filipwasil/fillwave/issues/58#issuecomment-188972660

https://shnoh171.github.io/gpu%20and%20gpu%20programming/2019/08/26/installing-glfw-on-ubuntu.html
Japanglish Tech Talk #2 プレゼンテーション紹介

# Japanglish Tech Talkとは？

Japanglish Tech Talkは、東京で開催されるエンジニア向けの英語限定LTイベントです！日本では大半の会話が日本語で行われるため、英語を話す機会が少ないのが現状です。そこで私たちは、東京でカジュアルにLTイベントで英語を話せる機会を提供するためにこのイベントを企画しました。

# Japanglish Tech Talk #2 開催報告 :-D

2024年8月21日に第2回Japanglish Tech Talkを開催しました。ここでは簡単にプレゼンテーションの内容をご紹介します。


- [Japanglish Tech Talk#2イベントページ](https://japanglish.connpass.com/event/323995/)
- [Japanglish YouTube チャンネル](https://www.youtube.com/channel/UCKC2d4f-k-f4KeRs_YV9q_g)

### Thank you for sponsoring!
今回開催にあたり、[Ichizoku](https://ichizoku.io/)様と[e-dash](https://e-dash.io/)様にご協力いただきました。<br>改めてありがとうございました！🙏

**Ichizoku様**
<img width="230" height="64" src="https://ichizoku.io/wp-content/uploads/2023/02/logo-main.svg" >
Blog: [https://ichizoku.io/category/sentry/](https://ichizoku.io/category/sentry/)


**e-dash様**

<img  width="300" height="auto" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498701/58ab0ed4-9bff-d7dc-935a-0ead6a29cc70.png" >

Tech Blog: [https://zenn.dev/p/edash_tech_blog](https://zenn.dev/p/edash_tech_blog)

## 発表内容

### チームのためのリポジトリ管理
- [YouTube](https://youtu.be/1BiM90YiSyk?si=fzx9VHAn7_96Pr-X&t=414)
- 発表者: Metra

チームの規模に応じたリポジトリの運用と、それに関連する知識について包括的に説明しました。開発プロセスを体系的に理解するのに役立つ内容でした。

### AWS Step Functions 入門
- [YouTube](https://youtu.be/1BiM90YiSyk?si=DcIawiuZIibkD6me&t=1031)
- 発表者: Koya

AWS Step Functionsの紹介とユースケースについて説明しました。

### グローバルチームからの洞察：初めての国際協力者の視点
- [YouTube](https://youtu.be/1BiM90YiSyk?si=HcZYTVRsT7pWkCny&t=2525)
- 発表者: 近藤義文

グローバルチームでの働き方とグローバル環境にいるためのマインドセットについて説明しました。

### サンフランシスコで開発者として働くことの違い
- [YouTube](https://youtu.be/1BiM90YiSyk?si=2EPetiM-GFiZATWS&t=1807)
- 発表者: Naru

サンフランシスコに出張した際に感じた、日本との違いを紹介しました。

### 外部モニターの使用をやめた理由
- [YouTube](https://youtu.be/pHGAMgpR6yI?si=ZCA125DlsswGSLNa&t=893)
- 発表者: Buzo

外部モニターの使用をやめた理由について、さまざまな視点から説明しました。

### Radix UIとカスタムCSSを統合したUIコンポーネントの開発
- [YouTube](https://youtu.be/pHGAMgpR6yI?si=o6RzW0J_IQppMI6a&t=1367)
- 発表者: Tamtam

Radix Primitivesについて話し、それを使用した経験を共有しました！

# 次回イベント開催予定！

参加者総数が30名を超え、今後ボランティアとして協力してくださる方々とも繋がることができました。需要が高いため、このイベントを定期的に開催する予定です！XD

![イベント写真](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9urq4el4ypqrnxlylcg.jpg)

# 主催者について

- [Tamtam](https://x.com/TamtamFitness)
- [Naru](https://x.com/1026NT)

Japanglish Tech Talkは、TamtamとNaruが共同で企画・運営しているイベントです。エンジニアの皆さんに英語でのコミュニケーションの機会を提供し、国際的な技術交流を促進することを目指しています。
Japanglish Tech Talk #1 プレゼンテーション紹介

# Japanglish Tech Talkとは？

Japanglish Tech Talkは、東京で開催されるエンジニア向けの英語限定LTイベントです！日本では大半の会話が日本語で行われるため、英語を話す機会が少ないのが現状です。そこで私たちは、東京でカジュアルにLTイベントで英語を話せる機会を提供するためにこのイベントを企画しました。

# Japanglish Tech Talk #1 開催報告 :-D

2024年6月19日に第1回Japanglish Tech Talkを開催しました。ここでは簡単にプレゼンテーションの内容をご紹介します。

- [Japanglish Tech Talk#1イベントページ](https://japanglish.connpass.com/event/316285/)
- [Japanglish YouTube チャンネル](https://www.youtube.com/channel/UCKC2d4f-k-f4KeRs_YV9q_g)

### Thank you for sponsoring!

今回開催にあたり、[Ichizoku](https://ichizoku.io/)様と[RAKSUL](https://corp.raksul.com/en/)様にご協力いただきました。改めてありがとうございました！🙏


**Ichizoku様**
<img width="230" height="64" src="https://ichizoku.io/wp-content/uploads/2023/02/logo-main.svg" >
Blog: [https://ichizoku.io/category/sentry/](https://ichizoku.io/category/sentry/)


**ラクスル様**

<img  width="230" height="auto" src="https://imgur.com/RIocR2G.png" >

Tech Blog: [https://techblog.raksul.com/](https://techblog.raksul.com/)

## 発表内容

### Geminiを使用したAndroidアプリUIの生成
- [発表資料](https://speakerdeck.com/musayazuju/generate-android-app-ui-with-gemini)
- 発表者: Musa

Google I/O 2024で紹介された「Gemini」機能について説明しました。想像していたデザインの詳細と一致しない正確性、画像入力オプションの不足、初期コンパイルエラーなど、今後の改善に期待が寄せられています。

### 初めてのインフラ構築：EC2からECSへの道のり
- [発表資料](https://speakerdeck.com/zakisankazu/2024-06-19-japanglish-tech-talk-building-my-first-infrastructure-the-way-from-ec2-to-ecs)
- 発表者: Zaki

PHP/Laravelウェブアプリケーションのコンテナ化とEC2からECSへの移行の取り組みを紹介しました。今後はログ管理方法の改善、セキュリティ対応の知識、チーム内でのインフラ運用スキルの向上に焦点を当てていきます。

### Next.js、Golang、Auth0を使用したアプリケーションの再構築
- [発表資料](https://speakerdeck.com/kohekohe/replaced-the-app-with-next-dot-js-golang-and-auth0-20240619-a17b3f3a-c32b-4858-b5eb-d5365efbc456)
- 発表者: kohekohe

エンジニアチームの構築と既存アプリケーションを最新技術で置き換えた経験について発表しました。特にユーザーデータ移行の話には共感を覚えました。

### バックエンドエンジニアのためのhtmx
- [発表資料](https://speakerdeck.com/nakamurakzz/htmx-for-backend-engineer)
- 発表者: Nakamura

フロントエンド開発が得意ではないバックエンドエンジニアが、htmxを使用してインタラクティブなウェブアプリケーションを簡単に構築できる方法を紹介しました。

※他の発表内容は後日共有予定です！

# 次回イベント開催予定！

参加者総数が30名を超え、今後ボランティアとして協力してくださる方々とも繋がることができました。需要が高いため、このイベントを定期的に開催する予定です！XD

![イベント写真](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlecsgkw9exdg0ffg8sc.png)

# 主催者について

- [Tamtam](https://x.com/TamtamFitness)
- [Naru](https://x.com/1026NT)

Japanglish Tech Talkは、TamtamとNaruが共同で企画・運営しているイベントです。エンジニアの皆さんに英語でのコミュニケーションの機会を提供し、国際的な技術交流を促進することを目指しています。
TypeScript ジェネリクス まとめ

## ジェネリクス (generics)とは
TypeScriptで重要な文法/機能の一つ、日本語だと「総称型」

抽象的な型のテンプレートを用意し、実体を作る時に具体化する。
つまり動的に型を設定する事が出来るという事。
この機能によって様々なユースケースで**共通化**が楽にでき、型エイリアス、Class、関数コンポーネントでも使えます。

**このジェネリクスを用いた共通化**に関して、[TypeScript公式](https://typescriptbook.jp/reference/generics
)で詳しく書かれていました、以下抜粋。

>型の安全性とコードの共通化の両立は難しいものです。
あらゆる型で同じコードを使おうとすると、型の安全性が犠牲になります。
逆に、型の安全性を重視しようとすると、同じようなコードを量産する必要が出てコードの共通化が達成しづらくなります。

>こうした問題を解決するために導入された言語機能が**ジェネリクス**です。

>ジェネリクスを用いると、型の安全性とコードの共通化を両立することができます。

#### ジェネリクスが解決する問題
ジェネリクスが具体的にどのような問題を解決するのか見ていきましょう。ここに、chooseRandomlyString()という普通の関数があります。この関数は、2つの文字列を引数に受け取り、五分五分の確率で第1引数か第2引数の値を抽選して返します。

```typescript
function chooseRandomly<String>(v1: <string>, v2: <string>): <string> {
  return Math.random() <= 0.5 ? v1 : v2;
}
```
この関数では、引数が数値、URLオブジェクトなどのユースケースに対応できない、以下のように複製させるとコード量が増えて管理が面倒になる。
```typescript
function chooseRandomly<Number>(v1: <number>, v2: <number>): <number> {
  return Math.random() <= 0.5 ? v1 : v2;
}
```

そこでジェネリクスを使い、以下の様に**型の安全性を維持しながら、コードを共通化**します。

```typescript
function chooseRandomly<T>(v1: T, v2: T): T {
  return Math.random() <= 0.5 ? v1 : v2;
}
```
`<T>` は型変数名の定義です。慣習としてTがよく使われますが、AでもTypeでも構いません。
関数の引数の型や戻り値の型として書かれたTは型変数を参照しています。

>ジェネリクスはコードの共通化と型の安全性を両立してくれる言語機能です。
汎用的なコードをさまざまな型で使えるようにしたい際、ジェネリクスを使う。


### anyとの違い
型をanyにしてしまう問題点は、戻り値の型もanyになってしまうため、コンパイラのチェックが行われなくなり、バグを生みやすくなることです。つまり、型の安全性が損なわれるということです。


## まとめ
• コードの共通化すると、型の安全性が弱まる。
• 型の安全性を高めると、コードの共通化が難しくなる。
• ジェネリクスは、コードの共通化と型の安全性を両立するための言語機能。
• ジェネリクスは、型も引数のように扱うという発想。
NUCLEO-F446RE　Lチカ

# NUCLEO-F446RE

初期導入、Lチカまでの資料まとめ　随時更新。

![IMG_4909.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/d425c9b6-3b0a-863c-305c-913cfed8e004.jpeg)

# ０．ボードへの電源供給　データシートUM1724
![IMG_4906.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/b8b57537-8b5f-47bf-5635-9855cfede13b.jpeg)

:::note info
**JP5:
E5V:外部電源（7V～12V Max 800mA) 
U5V:USB供給**
:::

![STM32電源配線.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/e4866fe5-05b9-085b-9a41-fcefc4ef2d81.jpeg)

![STM32電源.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/5adc339c-f6c1-d3d6-f0f3-7530dc617c84.jpeg)

# １．LLコード自動生成画面設定
**データシート：UM1725  Description of STM32F4 HAL and low-layer drivers**
project設置画面で前もってHALまたはLLを、指定しておく。
![LLコード設定画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/8d22c935-b0b9-1075-8240-f5ac41e2c7c2.png)

# ２．GPIO出力LLライブラリー
:::note 

![IMG_4913.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/d8b70f5c-af94-500d-c862-a6cdc41cf0f2.jpeg)


**＜出力High＞
__STATIC_INLINE void LL_GPIO_SetOutputPin (GPIO_TypeDef * GPIOx, uint32_t PinMask)**
ex.PB5ピンの場合 LL_GPIO_SetOutputPin(GPIOB,LL_GPIO_PIN_5);
**＜出力Low＞
__STATIC_INLINE void LL_GPIO_ResetOutputPin (GPIO_TypeDef * GPIOx, uint32_t PinMask)**
ex.PB5ピンの場合 LL_GPIO_ResetOutputPin(GPIOA,LL_GPIO_PIN_5);
:::
(BizRobo!)CSVをHTMLとして開く方法

# はじめに
BizRobo!でCSVを開く際、デフォルト設定でファイル読込して開く場合、以下のようにCSV
として内部メモリ内に展開してCSV形式として表示させるか、テキストデータを変数に格納するかのどちらかがほとんどだと思います。
しかし、HTMLとして開くことも可能であることはご存知でしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/6dfba53d-49d6-07fa-82ba-d6b493f9ce7c.png)
※AI生成したテストデータなので実際の住所や個人名ではありません


今回はHTMLとして開く方法についての記事です。

# 設定方法
設定は簡単です。
「ファイル読込」ステップのオプションか、ロボットの設定を開き、[レガシー]タブを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/c96ccaa9-e97e-b061-adc6-9a573533de20.png)

レガシータブのフォーマット処理を以下のように「クラシック ローディング」にすることで、CSVをHTMLに変換して開くことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/0cf67a4a-a1a5-386c-71a3-d28707904ffb.png)

ちなみにこの画面で「ExcelからHTMLへ変換」にチェックを入れると、ExcelもHTMLとして開くことができます。

HTMLとして開くと、以下のようにテーブルとしてHTML表現された状態で表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/a665ab8d-8e7c-27a2-3444-e9ceb3c072c4.png)


# まとめと有用性
設定は非常に簡単ですが、CSVからの抽出方法に1つの選択肢が増えれば幸いです。

デフォルト設定でブラウザに開くと、そこから値を抽出する手段が「データ行繰り返し」をして1行毎にループを回して抽出するしかなく、特定のデータが含まれる行のデータのみ利用したいときは、一度抽出した値で判定処理をし、合致したときだけ後続処理に進ませる動作をさせる必要があります。
しかし、HTMLとして開いた場合は、通常のWebサイトを開いた場合と同様の動作ができるため「名前付きタグ設定」をしてそのタグと同じ行や列の値、そのタグの後にある値のみを抽出するということも可能で、自由度が高くなります。
もちろんテキストとして抽出して正規表現やコマンドラインを駆使してどうにかできる方もいるとは思いますが、お手軽な方法の一つとして試してみてはいかがでしょうか。
Chromeで右クリメニューのリーデンィングモードを非表示にする方法

どうもりょうです。
今回はChromeでのリーデンィングモードの非表示設定の方法の解説です。

## リーディングモード
リーディングモードは、ページからテキストだけを抽出して表示する機能です。
こんなかんじでサイドパネルで表示されます。
ニュースサイト読むときとかには良い機能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/96fea506-7e6e-e7b3-6feb-dd45c3a25244.png)

Chromeのバージョンによっては右クリメニューのときに出てくるので誤タップが多くなって本当にイライラします。
正直使わないし邪魔なので消しちゃおうという記事です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/e9bd5160-9daf-549d-868b-eba91fe0bda3.png)

## 消し方
まず検索バーにchrome://flagsと入れて別タブで開きます。
そこで`Reading Mode`と検索してDisabledにし、RESTARTを押せば完了です。
使いたいときはEnabledにしてください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/af286baf-9e9a-cb52-94bb-38dacae88a02.png)

## 現在
ChromeOS ver127時点では右クリメニューのは廃止され、設定しておけば右上からリーディングモードで見ることができます。
ただ124や125のまま更新してない人は右クリで表示されてストレスたまるので消すのをオススメします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/fe6e4ab9-2cf5-4cf1-b074-3477bb5d7573.png)

## おわり
今回はリーデンィングモードの非表示の方法でした。
現在の新しいバージョンでは必要ない記事ですが、学校のPCなどは更新してない人も多いので快適に使えるようにしましょう笑

わからないことあったら書いてくれれば答えていきます。

**Discordにいる荒らしの情報や対策方法の共有をしている自鯖です**
ぜひ参加お願いします↓↓↓↓

https://discord.gg/ESRGwGQhxc
Spring で既存のBeanをいじらずにJSONへの出力内容を調整

# はじめに
DAOから取得した既存のBeanのデータをそのままレスポンスにJSONとして出力したいけど、いらない項目があったり、出力形式を少し変更したり、プロパティ名を変更したりしたい、ということがあるかと思います。
そんな場合の対処法を紹介します。

# やり方

まず、以下のよな既存のBeanがあったとします。

```java:既存のBean
@Data
public class User {
    String userId;
    String userName;
    String password;
    Date birthday;
}
```

上記のうち、userNameは、nameというプロパティ名で、birthdayは"yyyy/mm/dd"形式で、そして、passwordは出力したくない、というケースがあったとします。
そういう場合の例です。

```java:コントローラー
@RestController
@Transactional
public class UserListController {

	@Inject
	private userMapper userMapper;

    // produces属性に"application/json;charset=UTF-8"を追加しないと日本語文字列が文字化けする
	@PostMapping(path = "/userlist", produces = "application/json;charset=UTF-8")
	public String userList() throws JsonProcessingException {

		List<User> users = UserMapper.selectAll();

		ObjectMapper mapper = new ObjectMapper();
		// Userで定義されている項目について、JSONに出力する項目定義を追加する
		mapper.addMixIn(User.class, UserView.class);
		return mapper.writeValueAsString(users);
	}

    // JSONに出力する項目の定義
	static abstract class UserView {

        // 出力しないフィールド
		@JsonIgnore
		String password;

        // 出力パターンを指定
		@JsonFormat(pattern = "yyyy/MM/dd", timezone = "Asia/Tokyo")
		String birthday;

        // 出力するプロパティ名を指定
		@JsonProperty("name")
        String userName
	}
}

```

こんな感じで、JSONに出力する項目定義用の抽象クラスを作成して、``ObjectMapper#addMixIn(既存Bean.class,作成した定義クラス.class)``を実行して、``writeValueAsString``メソッドでJSON文字列を生成すればOKです。
注意点としては、RequestMapping(GetMapping,PostMapping)の属性に``produces = "application/json;charset=UTF-8"``を付与しないと、日本語文字列が文字化けしてしまうので、別途指定が必要ということです。

なお、上記抽象クラスは、以下のようなインタフェースでも可能です。

```java
	static interface UserView {

		@JsonIgnore
		String getPassword();

		@JsonFormat(pattern = "yyyy/MM/dd", timezone = "Asia/Tokyo")
		String getBirthday();
  
		@JsonProperty("name")
        String getUserName();
 }

```
実行すると、こんな感じのJSON文字列がレスポンスに出力されます。
```json
{
    "userId": "yamada",
    "name": "山田　太郎",
    "birthday": "2000/03/05"
},
{
    "userId": "sato",
    "name": "佐藤　花子",
    "birthday": "2000/05/09"
}
```
# 余談
* JsonFormatアノテーションの``timezone``の指定をしないと、デフォルトでUTCが適用されてしまうので必須。デフォルトのタイムゾーンを適用してくれないので注意
* Spring Bootの場合は、@JsonMixinを使用すれば、ObjectMapperのインスタンスを生成する作業以降を行わなくても出来そうだが、Spring MVCでは未対応っぽい

# Beanの編集OKで同じBeanを複数処理で使いまわす場合
JsonViewを利用する方法があります。
以下のサイトに説明があります。

https://terasolunaorg.github.io/guideline/current/ja/ArchitectureInDetail/WebServiceDetail/REST.html#how-to-extend

# 参考サイト
以下のサイトを参考にしました。

https://qiita.com/rch850/items/30825e6ff0811fdc011d
Reactのクリーンアップ処理を行わないと大変になることがわかる重要性がわかるデモアプリ

# クリーンアップ処理の必要性がいまいちわからない
以下はクリーンアップ処理をせずタイマーを10万個単位で追加するデモです。
実際はこんなことにはならないと思いますが。

https://claude.site/artifacts/7e6ea5b9-b8cf-44ff-a502-a6206ac9466e

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69647/cd7984dd-a44e-e612-902e-8c654c256526.png)
```react
import React, { useState, useEffect, useCallback } from 'react';
const MassiveMemoryLeakDemo = () => {
  const [timerCount, setTimerCount] = useState(0);
  const [memoryUsage, setMemoryUsage] = useState(0);
  const [isAdding, setIsAdding] = useState(false);
  // メモリ使用量を更新する関数
  const updateMemoryUsage = useCallback(() => {
    if (window.performance && window.performance.memory) {
      setMemoryUsage(Math.round(window.performance.memory.usedJSHeapSize / (1024 * 1024)));
    }
  }, []);
  // タイマーを追加する関数
  const addMassiveTimers = useCallback(() => {
    setIsAdding(true);
    const startTime = performance.now();
    // タイマーを一括で追加
    for (let i = 0; i < 100000; i++) {
      setInterval(() => {
        // 空の関数
      }, 1000000); // 非常に長い間隔を設定して、実際の処理回数を減らす
    }
    setTimerCount(prevCount => prevCount + 100000);
    updateMemoryUsage();
    setIsAdding(false);
    const endTime = performance.now();
    console.log(`100,000 タイマーの追加にかかった時間: ${endTime - startTime} ミリ秒`);
  }, [updateMemoryUsage]);
  // メモリ使用量を定期的に更新
  useEffect(() => {
    const memoryUpdateInterval = setInterval(updateMemoryUsage, 1000);
    return () => clearInterval(memoryUpdateInterval);
  }, [updateMemoryUsage]);
  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold mb-4">大規模メモリリークデモ</h1>
      <button 
        onClick={addMassiveTimers}
        disabled={isAdding}
        className="bg-red-500 text-white px-4 py-2 rounded mb-4 disabled:bg-red-300"
      >
        {isAdding ? '追加中...' : '100,000個のタイマーを追加'}
      </button>
      <p className="mb-2">追加されたタイマーの総数: {timerCount.toLocaleString()}</p>
      <p>推定メモリ使用量: {memoryUsage} MB</p>
      <p className="mt-4 text-sm text-red-600 font-bold">
        警告: このデモは意図的に大量のメモリリークを引き起こします。ブラウザのクラッシュや
        システムの不安定化を招く可能性があります。教育目的でのみ使用してください。
      </p>
    </div>
  );
};
export default MassiveMemoryLeakDemo;
```
Could not find gozip for packaging. Using DotNetZip to package. のエラーを表示しないようにしたメモ

## 概要
package.jsonに下記コードを書いてGitBashで実行したら、削除はできるが警告が表示される状態となった。
環境はwindows。

```
    "clean": "rm -rf dist",
```
    
```
Could not find gozip for packaging. Using DotNetZip to package. This may cause problems preserving file permissions when using in a Linux based environment.
```

## 対処

rimrafを使う。

```
npm install --save-dev rimraf
```

```diff
-    "clean": "rm -rf dist",
+    "clean": "rimraf dist",
```
ProxmoxでVM用にDHCPをSNATで提供する。

例えば、VMインストール時にインターネット用のIPを前もって採番管理するのってちょっと面倒ですよね？こんな時、ホストの管理IPとVM間にDHCPがあれば何も準備せずインストールできるので楽です。また、特定のVLAN等に設定することも可能です。
参考：
[Setup Simple Zone With SNAT and DHCP](https://pve.proxmox.com/wiki/Setup_Simple_Zone_With_SNAT_and_DHCP)
# 前提
* ホストの管理IPにSNATでDHCPをVMに提供する場合の手順とする
* Firewallの設定は割愛
# インストール
* dnsmasqのインストール（All）
ホストにログインし下記コマンドを実施。
既にdnsmasqがインストールされていないことを確認してからインストールする。
※他用途で使用しいる場合は要検討
```
# systemctl list-unit-files | grep dnsmasq
# apt install dnsmasq
```
# SDN設定
* ゾーン（Simple）を追加する
入力箇所はIDと自動DHCPの☑ボックス。
![20240823_001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352455/72c55f5b-081f-d832-ab02-aa300a04953e.jpeg)
  <br>
* Vnetを追加する
入力箇所は名前とゾーン（上記で作成したゾーンを選択）
![20240823_002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352455/f167b0f6-96e6-edde-c00e-b2fb709165a9.jpeg)
  <br>
* サブネットの作成
[IP Address]/[Prefix]の形式でサブネットを入力してSNATを☑。
※サブネット内の適当なゲートウェイを入れておけば作業用端末からSSHできます。
![20240823_006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352455/48e7db1f-ed44-c472-d6a1-5b19888831a7.jpeg)
右のタブからDHCPのレンジを設定
![20240823_005.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352455/53e49d53-673e-6832-bec8-4d5ccbd8766f.jpeg)
# VMへの設定方法
* VMのネットデバイスを設定
VMのハードウェア設定にてネットデバイスのブリッジに作成したvnetを設定
![20240823_007.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352455/b7692392-e409-c561-2c4e-e262f4e2161c.jpeg)
# ルーティング設定
* スタティックルートの設定
作業端末にて192.168.112.0/24の宛先はインターフェイス番号XXで[Host IP]を経由するというルーティングを管理者権限で設定する。但し、1サブネットに対し、設定できるホストのIPは一つ。
```
> route add -p 192.168.112.0 mask 255.255.255.0 [Host IP] if XX
```
以上
日本工作機械工業会の統計ページからPDFリンクを自動抽出するPythonスクリプト


日本工作機械工業会（JMTBA）の統計ページから、各月の統計情報を含むPDFリンクを自動的に抽出するPythonスクリプトを紹介します。このスクリプトは、BeautifulSoupとrequestsライブラリを使用して、指定されたページからPDFファイルのリンクと対応する日付を抽出するプロセスを自動化します。

https://www.jmtba.or.jp/statistics/

## ステップ1: メインページの内容を取得
まず、指定されたベースURLから、統計情報が含まれるリスト項目を抽出します.

```python
import requests
from bs4 import BeautifulSoup

def extract_statistics_pdfs(base_url):
    # ベースURLのページを取得
    response = requests.get(base_url)
    response.raise_for_status()

    # BeautifulSoupでHTMLを解析
    soup = BeautifulSoup(response.text, 'html.parser')

    # すべてのリスト項目を取得
    list_items = soup.select('li.statisticsSec__listItem')

    pdf_links = []
```
requests.get(base_url): Pythonのrequestsライブラリを使用して、指定したURLからページのHTMLコンテンツを取得します。

soup = BeautifulSoup(response.text, 'html.parser'): BeautifulSoupを使用して、取得したHTMLを解析可能なオブジェクトに変換します。

list_items = soup.select('li.statisticsSec__listItem'): HTML内の統計データが含まれるリスト項目をすべて抽出します。
## ステップ2: 各リスト項目からPDFリンクと日付を取得
次に、抽出したリスト項目からPDFリンクとそれに対応する日付を取得します

```python
    # 各リスト項目をループ
    for item in list_items:
        # 日付の取得
        date_text = item.select_one('span.statisticsSec__listItemSpan').get_text(strip=True)

        # PDFリンクの取得
        link = item.select_one('a.statisticsSec__listItemLink').get('href')

        # 日付とリンクをリストに追加
        pdf_links.append((date_text, link))

    return pdf_links
```

**日付の取得:**
date_text = item.select_one('span.statisticsSec__listItemSpan').get_text(strip=True): 各リスト項目内の<span>タグから日付テキストを抽出します。

**PDFリンクの取得:**
link = item.select_one('a.statisticsSec__listItemLink').get('href'): 各リスト項目内のaタグからPDFリンクを取得します。

**日付とリンクのペアをリストに追加:**
pdf_links.append((date_text, link)): 取得した日付とリンクをペアにしてリストに追加します。

## 最終結果の出力
抽出された日付とPDFリンクのペアを表示します。
```python
# 使用例
base_url = 'https://www.jmtba.or.jp/statistics/'  # ベースURL
pdf_links_with_dates = extract_statistics_pdfs(base_url)

# 取得した日付とPDFリンクを表示
for date, pdf in pdf_links_with_dates:
    print(f"{date}: {pdf}")
```
T3 Stackについて学んでみた

## 学んだきっかけ

これまでの個人開発では、フロントエンドにNext.js、バックエンドにSpringBootを使用して開発を行ってきました。

しかし、Next.jsはバックエンド開発も可能であるため、その便利さを実感したく、フルスタックで開発してみようと思い、API RouteやPrismaについて調べていました。

その際に、T3 Stackというものを知り、Next.jsやTypeScript、Tailwind CSSなど、既に使ったことのある技術が含まれていたため、これを機にT3 Stackについて学んでみました！

## T3 Stackとは？

T3 Stackとはsimplicity（簡潔さ）、modularity（モジュール性）、full-stack type safety（フルスタックの型安全）に焦点を当てた開発手法です。

そして上記を実現するために以下6つの技術スタックを使用します。（個々の説明は割愛）

- Next.js
- TRPC
- NextAuth
- Prisma
- Tailwind CSS
- TypeScript

また、以下コマンドにてプロジェクトを作成すれば、上記６つの技術スタックの基本的な設定をあらかじめ用意してくれます。

とても便利です。

```bash
npm create t3-app@latest
```

コードの中身については、今回は記述しませんが、自分が学んだUdemy講座とYoutubeのリンクを貼っておきますので、ぜひ興味のある方は視聴してみてください。

https://www.udemy.com/course/t3-stack-nextjs-trpc-web/?couponCode=SKILLS4SALEJP

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


## 使ってみての感想

### T3 Stack全体として

- 以前、Next.jsとSpring Bootで開発していた時は、バックエンドではControllerでフロントエンドからの処理を捌いていたが、T3 Stackでは、TRPC で定義した関数（プロシージャ）にバックエンドの処理を記述し、それを直接フロントエンドから呼べる（しかも型安全に）ためすごい便利。（Server Actoinsなども今後学びたい）
- TRPC により、フロント←→バック間の型の整合性が担保されるため、TypeScriptの利点をより活かした開発手法だと感じた。

### Next.js

- フロントエンドとバックエンドを同プロジェクトで開発できるのは便利
    - デプロイが一回で良いのは楽。
    - シンプルにIDEを切り替えないで良いのが楽。

### TRPC

- zodによる型定義がめちゃくちゃ便利。

### Prisma

- Prisma Studio（ブラウザのGUI操作でDBを照会•更新できる）が便利。

### NextAuth

- ポートフォリオで使用したFirebase Authenticationと似ていた。

## 最後に

T3 Stackを使用することで、高機能のアプリケーションをスピーディーに作成できると感じました。

今回、TRPCやPrisma、NextAuthについては、初めて学んだため、さらにもっと詳しい使い方について今後学んでいきたいと感じました。
CSVのパースで空文字とnullを区別する

## 背景
業務でCSV取込機能を作っていて、なめてかかっていたら詰まったので備忘録として残します

## 課題
以下のようなCSVを取り込む必要があり、
```csvs
"dummy","",,dummy
```
結果として、
```json
[
 "dummy",
 "",
 null,
 "dummy", 
]
```
を得たいとのこと
え…CSVはそもそも文字列しか扱えないものだと思ってた…`null`も考慮せなあかんの…

## PHPで頑張る
PHPには`fgetcsv`と`str_getcsv`があるけど、

https://www.php.net/manual/ja/function.fgetcsv.php

https://www.php.net/manual/ja/function.str-getcsv.php

どっちも以下のような結果になる
```php
str_getcsv('"dummy","",,dummy');
/*
[
 "dummy",
 "",
 "",
 "dummy", 
]
*/
```
公式のオプション見て色々試したものの、全然上手くいかないので凄く強引だけど以下で解決しました
```php
function parseCsvNullHandling($line): array
{
    $pattern = '/(?<=,|^)""(?=,|$)/';
    $replacement = '___BLANK_TEXT___';
    return array_map(function ($v) use($replacement) {
        return $v === '' ? null : ($v === $replacement ? '' : $v);
    }, str_getcsv(preg_replace($pattern, $replacement, $line)));
}

parseCsvNullHandling('"dummy","",,dummy');
/*
array(4) {
  [0]=>
  string(5) "dummy"
  [1]=>
  string(0) ""
  [2]=>
  NULL
  [3]=>
  string(5) "dummy"
}
*/
```
①正規表現で`開始位置"",`と`,"",`と`,""終端`の`""`を`___BLANK_TEXT___`に置換
②`str_getcsv`でパース後、`空文字`を`null`、`___BLANK_TEXT___`を`空文字`に変換

とりあえず出来たけど、考慮が漏れてそうでとても怖い…

## TypeScriptで頑張る
TypeScriptでは`parse-csv`を使用しました

https://csv.js.org/parse/

こっちも特に何も考慮しないとPHPと同じ結果になった
```TypeScript
parse('"dummy","",,dummy', {
    escape: "\\"
})
/*
[ [ 'dummy', '', '', 'dummy' ] ]
*/
```
こっちは`cast`オプションでクォートの有無が確認出来たのですんなり出来た

```TypeScript
import {parse} from "csv-parse/sync";

parse('"dummy","",,dummy', {
    escape: "\\",
    cast: (value, { quoting }) => {
        return value === '' && !quoting ? null : value;
    }
})
/*
[ [ 'dummy', '', null, 'dummy' ] ]
*/
```

## 感想
PHPはパーサー自作するしかないと思ってたのですが、パースはやっぱり標準関数に任せたいと思いこの方法になりました。（知り合いが案くれました）
でもやっぱりなんちゃって感が凄い
めちゃくちゃ不安
誰か良い方法あったら教えてください！
エンコードとデコード

# はじめに

先日、業務で文字列をエンコード、デコードする実装を行ったので、備忘録として記事にまとめたいと思います
この記事では、Ruby on Railsでのエンコードとデコードの基本的な使い方について説明します

# エンコードとデコードとは？

エンコードとデコードは、データを異なる形式に変換し、必要に応じて元の形式に戻すプロセスです
このプロセスにより、データの送信や保存時にセキュリティが確保され、データの整合性も維持されます

Ruby on Railsでは、`Base64`モジュールを使用してエンコードとデコードを行います
`Base64`モジュールを使用して、文字列のエンコードとデコードを簡単に行うことができます

## エンコード
エンコードは**データを特定の形式に変換する**手順です
例えば、バイナリデータをテキスト形式に変換することで、インターネット通信やデータベースにデータを保存する際にセキュリティが担保され、データが安全に取り扱えるようになります

以下は、ユーザーのパスワードをBase64でエンコードする例です
```
require 'base64'

original_string = "password123"
encoded_string = Base64.encode64(original_string) # エンコード

puts "エンコードされた文字列: #{encoded_string}"
// エンコードされた文字列: cGFzc3dvcmQxMjM=
```

## デコード
デコードは**エンコードされたデータを元の形式に戻す**手順です
デコードを行うことで、送信先や保存先でデータを正しく再現し、元の情報を取得することができます
例えば、`Base64`でエンコードされた文字列をデコードして、元のバイナリデータやテキストデータを取り出すことができます

下記は、上記でエンコードした文字列を`Base64`でデコードし、元の文字列に戻します
```
decoded_string = Base64.decode64(encoded_string) # デコード

puts "デコードされた文字列: #{decoded_string}"
// デコードされた文字列: password123
```

# 参考文献

https://qiita.com/3062_in_zamud/items/a251069e7aef703687b0

https://docs.ruby-lang.org/ja/latest/class/Base64.html
なぜ完璧なバグ検出プログラムは存在しないのか？【計算理論入門】

## 記事の内容
この記事では、計算理論の基本的な成果に触れたい。

それは、**理論的に存在できないプログラム**だ。

この事実は、現実的に重要である「完璧なバグ検出プログラム」の存在にも関係する。

具体例と証明の考え方をまとめたい。具体例にはPythonのコードを使用する。

### 注意
この記事内でいう「絶対に存在しないプログラム」は、書こうとすると必ず矛盾してしまい狙い通りの挙動が得られないプログラム、というイメージだ。厳密な表現ではないことに注意してほしい。



## 存在しないプログラム

かなり不自然な定義だが、以下のようなコードを考えよう。
「Pythonのコード」を入力として受け取るという関数だ。


```python
def notYesOnSelf(P):
    if P(P) == 'yes':
        return 'no'
    else:
        return 'yes'

```

面白いところはここからだ。
**この関数に自分自身を引数として与えたらどうなるのか？**

そうすると矛盾が生じる。よって、この関数、つまり、`notYesOnSelf()`は存在しないことが導かれる。
* P(P) = 'yes'と仮定すると、P(P)は'no'を出力する。矛盾。
* P(P) = 'no'と仮定すると、P(P)は'yes'を出力する。矛盾。

なぜこのような奇妙な関数を考えたのか。
それは、`notYesOnSelf()`は存在しないことが分かると、以下に示す`yesOnString()`,`yesOnSelf()`も存在しないことが示せるからだ。入力である`P`はPythonのコードを、`I`は文字列を表す。


```python
def yesOnString(P, I):
    if P(I) == 'yes':
        return 'yes'
    else:
        return 'no'
```


```python
def yesOnSelf(P):
    if P(P) == 'yes':
        return 'yes'
    else:
        return 'no'

```

なぜならば、`yesOnString()`,`yesOnSelf()`が存在すると仮定すると、`notYesOnString()`を作れてしまう。背理法の考え方だ。

`yesOnString()`から`yesOnSelf()`を作る。
```python
def yesOnSelf(progString):
    return yesOnString(progString, progString) 
```

`yesOnSelf()`から`notYesOnString()`を作る。`notYesOnString()`が作れてしまってはダメ。
```python
def notYesOnString(progString):
    val = yesOnSelf(progString)
    if val == 'yes':
        return 'no'
    else:
        return 'yes'
```




## yesOnString()が重要な理由
存在しないことがわかった`yesOnString()`は重要な意味を持つ。
* プログラムが他のプログラムを解析し、さまざまな入力に対して出力を生成することができる

ことを意味するからだ。

これは、喉から手が出るほどほしい、**「バグ検出」プログラム**の存在につながる。しかし、次に説明するように、否定的な結果が証明されている。


## 完璧なバグ検出プログラムは存在しない

```python
def crashOnString(P,I):
    if P(I)が例外を投げるとき:
        return 'yes'
    else:
        return 'no'
```
この`crashOnString()`が存在すると仮定すると、先ほどの`notYesOnSelf()`を導く議論と同じように矛盾を起こすプログラムを構成できてしまう。よって、`crashOnString()`は存在しない。

※この例では、わかりやすいように、例外を投げるようなケースだけをバグとして扱っている。しかし、そのほかのすべてのバグを見つけることはできないことも証明できる。

## 完全ではないが有効なアプローチは可能
任意のプログラムの完全なバグ検出ができないことは証明されている。しかし、特定のプログラムに対して、ある種類のバグの検出はさまざまなアプローチが研究されている。個別の工夫の価値はあるということだ。


## 参考
計算理論の基本的な話なので、検索すればすぐに情報を集められると思う。

Pythonコードによる具体例は次の本を参考にした。おすすめ。
『計算できるもの、計算できないもの　実践的アプローチによる計算理論入門』

この本についてはこちらの記事で紹介している。
[【数理論理学、数学基礎論、プログラム理論、計算論】 おすすめ入門本 まとめ](https://www.buchinuku.work/entry/2019/12/1)
Bash スクリプトで複数ファイルをチェックし、コピーする方法

この投稿では、Bash スクリプトを使って指定されたテキストファイル内のファイルパスを順にチェックし、それらのファイルが存在するかどうか、そしてサイズが 0 以上であるかを確認する方法について説明します。ファイルが存在し、サイズが 0 より大きい場合は指定されたフォルダにコピーされ、サイズが 0 の場合はそのファイル名が別の出力ファイルに記録されます。

#スクリプトの概要
このスクリプトは、以下の操作を行います:

1.入力ファイルの行ごとの読み取り: 入力ファイルは、ファイルパスが書かれたテキストファイルです。
2.ファイルの存在確認: 各ファイルパスについて、該当ファイルが存在するかどうかをチェックします。
3.ファイルサイズの確認: ファイルが存在する場合、そのサイズを確認します。
4.ファイルのコピーまたは記録: サイズが 0 より大きい場合、ファイルを指定されたフォルダにコピーします。サイズが 0 の場合、そのファイル名を出力ファイルに記録します。

スクリプトの内容
以下が、具体的なスクリプトの内容です：

```bash
#!/bin/bash

# 引数が正しく指定されているか確認する
if [ $# -ne 3 ]; then
    echo "使用方法: $0 input_file.txt output_folder/ empty_files_output.txt"
    exit 1
fi

# ユーザーからの入力を受け取る
input_file="$1"
output_folder="$2"
empty_files_output="$3"

# 出力フォルダが存在するか確認し、存在しない場合は作成する
if [ ! -d "$output_folder" ]; then
    mkdir -p "$output_folder"
fi

# 入力ファイルを1行ずつ読み込む
while IFS= read -r file_path; do
    # 行の前後の空白を削除
    file_path="$(echo "$file_path" | xargs)"

    # ファイルが存在するか確認する
    if [ -f "$file_path" ]; then
        # ファイルのサイズが0より大きいか確認する
        if [ -s "$file_path" ]; then
            # ファイルを出力フォルダにコピーする
            cp "$file_path" "$output_folder"
        else
            # ファイルのサイズが0の場合、ファイル名を出力ファイルに記録
            echo "$file_path" >> "$empty_files_output"
        fi
    else
        echo "ファイルが見つかりません: $file_path"
    fi
done < "$input_file"

```
#スクリプトの使い方
1. スクリプトの保存
スクリプトをファイルに保存します。例えば、check_and_copy.shという名前で保存します。

2. 実行権限の付与
スクリプトに実行権限を付与します。
```bash
chmod +x check_and_copy.sh
```
3. スクリプトの実行
以下のようにスクリプトを実行します：
```bash
./check_and_copy.sh input_file.txt /path/to/output/folder/ empty_files.txt
```
input_file.txt は、チェックしたいファイルパスが記載されたテキストファイルです。
/path/to/output/folder/ は、ファイルがコピーされるフォルダのパスです。
empty_files.txt は、サイズが 0 のファイルのパスを記録するファイルです。

#結果
ファイルが存在しない場合、エラーメッセージが表示されます。
ファイルが存在し、サイズが 0 より大きい場合は、指定されたフォルダにコピーされます。
ファイルが存在するがサイズが 0 の場合、そのファイル名が empty_files.txt に記録されます。
このスクリプトは、複数のファイルを効率的に管理するための基本的な方法を提供します。複数のファイルやプロジェクトを扱う際に役立つことでしょう。
【IntelliJ】データベースツールウィンドウで mysqldump したい

# はじめに
データベースの dump を作りたいときに、 Intellij のデータベースツールウィンドウから mysqldump できたらいいのになーと思い、調べてやってみました。

# やりかた
1. IntelliJ で、データベースツールウィンドウを開き、データベースを開く
1. dump したいデータベース or テーブルを右クリックする (複数選択可能)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/fae36472-4542-f115-77d5-4280f3c6b727.png)

1. `Import/Export` > `Export with 'mysqldump'...`
1. `Path to mysqldump:` に mysqldump のパスを設定
1. `Out path:` に dump ファイルの出力先を設定
1. Run!
1. 以上！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348896/f6efec6a-b911-04fd-5bea-e4253bedbbcc.png)


# 参考
https://pleiades.io/help/idea/export-data.html#create-a-full-data-dump-for-mysql-and-postgresql
JinjaのEnvironmentは undefined=StrictUndefined とするのがオススメ

# はじめに
JinjaはPythonで使える強力なテンプレートエンジンです。
たとえば、下記のように使うことができます。

~~~ python
import jinja2
e = jinja2.Environment()
t = e.from_string('私の名前は {{name}} です。')
s = t.render( { 'name': 'ジョンスミス' } )
print(s) # 私の名前は ジョンスミス です。
~~~

# 動機
テンプレートを書いてるときのタイポ、あると思います。
しかし、通常だとJinjaは未定義シンボルを空値として扱うだけです。

~~~ python
import jinja2
e = jinja2.Environment()
t = e.from_string('私の名前は {{nmae}} です。') # タイポ!
s = t.render( { 'name': 'ジョンスミス' } )
print(s) # 私の名前は  です。
~~~

テンプレートが短ければミスは明らかですが、長くなるとそうはいきません。

# undefined=StrictUndefined のススメ
なので `Environment` に `undefined=StrictUndefined` を渡しておくのがオススメです。

~~~ python
import jinja2
e = jinja2.Environment(undefined=jinja2.StrictUndefined)
t = e.from_string('私の名前は {{nmae}} です。') # タイポ!
s = t.render( { 'name': 'ジョンスミス' } )
# UndefinedError: 'nmae' is undefined
~~~

例外が出て、一発で気づけます。
未定義シンボルをテンプレートに書くことは通常ないと思うので、 `undefined=StrictUndefined` をデフォルトとしてもいいくらいだと思います。
Poetryを使ったPyPIおよびTestPyPIへのパッケージ公開手順をメモしてみた

Poetryを使用してPythonパッケージをPyPIおよびTestPyPIに公開する手順をメモしました。

実施する前には[PyPI](https://pypi.org/)、[TestPyPI](https://test.pypi.org/)のアカウントを作成し、トークンをもらいます。


# 1. PyPIおよびTestPyPIのAPIトークン設定

まず、PyPIとTestPyPIのAPIトークンをPoetryに設定します。

```bash
poetry config pypi-token.pypi "PyPIのAPI Token"
poetry config pypi-token.testpypi "Test PyPIのAPI Token"

```

# 2. TestPyPIのリポジトリURLを設定

TestPyPIのリポジトリURLをPoetryプロジェクトに設定します。

```bash
poetry config repositories.testpypi https://test.pypi.org/legacy/
```

# 3. パッケージのビルド
パッケージを公開する前に、まずビルドを行います。ビルドを実行すると、プロジェクトのルートディレクトリに`dist/`フォルダが作成され、その中に`.whl`ファイルと`.tar.gz`ファイルが生成されます。


```bash
poetry build
```


# 4. TestPyPIへの公開

ビルドが完了したら、まずはTestPyPIにパッケージを公開してテストします。

```bash
poetry publish -r testpypi
```

# PyPIへの公開

PyPIにパッケージを公開します。
```bash
poetry publish
```


うまくいけば、PyPIページで確認できるようになるはずです。

（アカウント名→自分のプロジェクト）


githubリポジトリがあれば忘れずにつけたほうが良いと思います。
Python モジュールのreloadを使ってコードを動的に更新

## 記事の概要
Pythonでプログラムを書いていると、コードを変更するたびにプログラムを再起動する必要があって面倒に感じたことはありませんか？本記事では、`importlib.reload()`という便利な機能を使って、プログラムを停止せずにコードの変更を反映する方法を紹介します。この技術を使えば、特に開発中のテストや調整が格段に楽になりますよ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/197ce6b4-0e70-1bfd-f887-ac1c8c3cbc16.png)


## なぜreloadが便利なの？

1. **時間の節約**: プログラムの再起動が不要になり、開発スピードが上がります。
2. **即時フィードバック**: コードの変更結果をすぐに確認できます。
3. **柔軟な開発**: 実行中のプログラムに新しい機能を追加できます。

## サンプルコード

以下に、簡単な例を示します。まず、2つのファイルを作成しましょう。

1. `greetings.py` - このモジュールを動的に更新します。
2. `main.py` - メインのプログラムで、`greetings.py`を呼び出します。

### greetings.py
```python
def say_hello():
    return "こんにちは、世界！"
```

### main.py
```python
import importlib
import greetings

# 1回目の挨拶
print("1回目:", greetings.say_hello())

# ここで greetings.py を編集します（後で説明）

# モジュールをリロード
importlib.reload(greetings)

# 2回目の挨拶
print("2回目:", greetings.say_hello())
```

## 実行手順と解説

1. まず、`main.py`を実行します：
   ```
   python main.py
   ```
   出力：
   ```
   1回目: こんにちは、世界！
   2回目: こんにちは、世界！
   ```
   
2. 次に、`greetings.py`を以下のように編集します：
   ```python
   def say_hello():
       return "こんにちは、動的な世界！"
   ```

3. もう一度`main.py`を実行します：
   ```
   python main.py
   ```
   出力：
   ```
   1回目: こんにちは、世界！
   2回目: こんにちは、動的な世界！
   ```

## 解説

- 1回目の実行では、両方の挨拶が同じでした。これは、プログラムが開始時に`greetings.py`を1回だけ読み込むためです。
- `greetings.py`を編集した後、2回目の実行で異なる結果が得られました。これは`importlib.reload(greetings)`によってモジュールが再読み込みされたためです。
- `reload()`を使うことで、プログラムを停止せずに`greetings.py`の変更を反映できました。

## 注意点

- すべての変更が`reload()`で反映されるわけではありません。例えば、クラスの定義変更は既存のインスタンスには影響しません。
- 大規模なプロジェクトでは、依存関係が複雑になるため、`reload()`の使用には注意が必要です。

## 実践的な使用例

- 開発中のWebアプリケーション（例：Django）で、サーバーを再起動せずにビューの変更をテストする。
- データ分析スクリプトで、データ処理関数を動的に更新しながら結果を確認する。
- 長時間実行される監視プログラムに、新しいチェック機能を動的に追加する。

## 公式の参考情報

Pythonの公式ドキュメントでは、`importlib.reload()`について次のように説明されています：

> "この関数は、以前にインポートされたモジュールを再読み込みするために使用されます。外部エディタでモジュールのソースファイルを編集し、Pythonインタープリタを終了せずに新しいバージョンを試したい場合に、この関数を使用します。"

詳しくは[Pythonの公式ドキュメント](https://docs.python.org/ja/3/library/importlib.html#importlib.reload)をご覧ください。

## まとめ

- `importlib.reload()`を使うと、Pythonのモジュールを動的に更新できます。
- この技術は開発時間の短縮と、即時フィードバックの取得に役立ちます。
- 単純なモジュールの更新には効果的ですが、複雑なケースでは注意が必要です。
- 開発中のテストや調整、特に長時間実行されるプログラムで有用です。

Pythonの`reload()`機能を使いこなせば、より柔軟で効率的な開発が可能になります。ぜひ、自分のプロジェクトで試してみてください！
playwrightで任意のapiをmock化

# TL;DR
PlaywrightのRouteクラスで指定したapiをモックすることが出来ます。
E2Eテストではサーバーエラーやタイムアウト時の挙動確認をする際に便利です。

公式の記事
https://playwright.dev/docs/api/class-route
# サンプル
ここではfulfill()とabort()を使ったサンプルコードと結果を示します。

* fulfill(): レスポンス内容を変更
https://playwright.dev/docs/api/class-route#route-fulfill
* abort(): リクエストを中断
https://playwright.dev/docs/api/class-route#route-abort

### パターン1: レスポンスボディを変更
```sample1.js
    // レスポンスパラメータを変更する
    await page.route("**/api/logIn", (route) => { //第一引数は任意のapiパス
      route.fulfill({
        status: 200,
        contentType: "application/json",
        body: JSON.stringify({ //返したいパラメータをセット
          hoge: "fuga",
        }),
      });
    });
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510732/b34a639e-6d94-7cda-f62c-95a425977208.png)
---
### パターン2: ステータスコードを変更
```sample2.js
//ステータスコード：504で返す
await page.route("**/api/logIn", (route) => route.fulfill({ status: 504 }));
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510732/bd0bfd8e-c60c-f7e5-c4f8-b29c92b05498.png)
---
### パターン3: リクエストを中断

```sample3.js
await page.route("**/api/logIn", (route) => {route.abort()});
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510732/8cc379a2-2776-5d8f-5b72-c0ebc3f968aa.png)
abortメソッドは下記の引数を指定することが出来ます。
|オプション|説明|
|--|--|
|aborted|操作が（ユーザーの行動により）中断|
|accessdenied|ネットワーク以外のリソースへのアクセス許可が拒否|
|addressunreachable|IPアドレスに到達できません。これは通常、指定されたホストまたはネットワークへのルートがないことを意味します|
|blockedbyclient|クライアントがリクエストをブロック|
|blockedbyresponse|レスポンスが満たされていない要件（例えば、'X-Frame-Options'や'Content-Security-Policy'の先祖チェック）とともに配信されたため、リクエストが失敗|
|connectionaborted|送信されたデータに対するACKを受信しなかった結果、接続がタイムアウト|
|connectionclosed|接続が閉じられた（TCP FINに相当）|
|connectionfailed|接続の試行が失敗|
|connectionrefused|接続の試行が拒否|
|connectionreset|接続がリセット（TCP RSTに相当）|
|internetdisconnected|インターネット接続が失わた|
|namenotresolved|ホスト名を解決できない|
|timedout|操作がタイムアウト|
|failed|一般的な失敗が発生|
Endpoint Administrator Associateの学習

### はじめに
クライアント環境に関する業務に携わることもあり、Endpoint Administrator Associateの学習をしました。

### 学習サイト
https://learn.microsoft.com/ja-jp/credentials/certifications/modern-desktop/?practice-assessment-type=certification

＜学習概要引用＞
●エンドポイントの ID、セキュリティ、アクセス、ポリシー、更新プログラム、アプリを管理する。
●さまざまな種類のオペレーティング システム、プラットフォーム、デバイスでエンドポイントを効率的に展開し、管理するためのソリューションを実装する。
●Microsoft Intune、Windows 365、Windows Autopilot、Microsoft Defender for Endpoint、Microsoft Entra ID を使用して、エンドポイントを大規模に実装し、管理する。

上記で特に私の業務に絡んでいたところは、「Microsoft Intune」「Windows Autopilot」です。Intune管理センターやEntra管理センター上での作業が多かったです。
例えば、Windows Autopilotを利用するために、WindowsPCの管理方法を変更やキッティング要件（登録プロファイル等）を定めたり、Intune管理をするために、準拠条件を定め、元々利用していたMDMからInutneへの移行等を経験したりしました。
付随して、WHfBや条件付きアクセスの設定・SSO等、認証に関わる変更も行いました。

### 学習方法
①コース受講
サイト内に、下記キャプチャのようにコースが設けられているので、コースに沿って学んでいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2745850/e0bfa11f-76e3-f496-7c8f-8744ce01b89e.png)

②試験に向けた練習
50問ランダムで出題される練習問題を受けました。
現時点では、本番試験が未受講なので、練習問題と本番試験の類似性はわかっていない状況です。

### 学習しての感想
主に文章ベースの体系的な学習になるため、業務に大きく活きるとはいいきれないかな思いました。ただ、用語や概念の整理には利用できるため、無駄になることはないと思います。
実際に管理センターに触れて、コース内で表現されているものと照会することで、必要な知識に繋がっていくと感じています。

### 今後について
折角、業務で携わっていることもあり、
認定資格「Microsoft 365 Certified: Endpoint Administrator Associate」の取得も目指そうと考えています。

2024年9月17日以降に試験形態が大きく変わるようなので、それ以降で受験になるかと思います。
【Go】psqlコマンドを実行し、テストデータを作成する方法

# はじめに
DBに接続したテストを実行する前に、テストデータを作成したいケースに対応する方法を記事にします

# フォルダ構成
こちらの`repositories`フォルダのテストコードを参照ください
https://github.com/AppDeveloperMLLB/todo_app/tree/main/repositories

`repositories/testdata`にテストで実行するsqlファイルを格納しています
テストでsqlファイルを実行するのは`main_test.go`となります

# 実際のコード
実際のコードは、setupTestDataメソッドを参照してください。
（Githubのコードとは、一部、変えています）
```go
cmd := exec.Command(
  "psql",
  "-h",
  "127.0.0.1",
  "-U",
  "test",
  "-d",
  "todo_db",
  "-f",
  "./testdata/createTable.sql")
cmd.Env = append(os.Environ(), "PGPASSWORD=password")
err := cmd.Run()
```

ポイントは、`cmd.Env = append(os.Environ(), "PGPASSWORD=password")`となります。
こちらを追加することで、パスワードなしで実行ができます。

実際にコマンドラインから実行するときも、`PGPASSWORD=password psql -h  127.0.0.1 -U test -d todo_db -f ./db/createTable.sql`とすることで、パスワードを入力なしでsqlファイルを実行できます。
docker-compse でローカルイメージを使う

# 利用シーン
　実は、システムを docker-compose 環境を gzip 提供して、解凍したらスクリプト一発でインストールしたいことってありますよねえ。

 - docker image はネットアクセスでは取得できないから、ローカルのイメージを使いたい。
 - バージョンアップ時に、イメージだけ提供したい。

でも docker-compose の image 定義はどこぞにとりに行ってしまうし。

# docker-compose の誤解
 「docker-compse でローカルイメージを使うには」　こうしたヘルプ投稿は結構多いんですが、これちょっとした勘違いなんです。　僕も image に tar.gz 書けないよ、って思ったことがります。
 
　ですが、そもそも ローカルの docker 環境に docker-compose.yml の image で定義した イメージがあれば、それ使ってくれるんです。　つまりは、

 - docker save で作った dockerイメージの tar.gz を
 - docker-compose up 前に docker load で ローカル環境にロードしておけば
 - docker-compose up 時には、それを使ってくれるんです。

# 具体的な docker 操作

## make 環境
 ```
docker build -t {Target}:{version} .
docker save {Target} | gzip > {TargetImage}.tar.gz

docker-compose.yml
    :
  services:
    xxx-system:
      image: {Target}:latest
      container_name: {コンテナ名}
    volumes:
        :

volumes:
  :

 ```

## デプロイ環境 (インストール時)
 ```
#
# docker イメージをローカル環境にロード
#
gzip -d {TargetImage}.tar.gz -c | docker load

    docker image ls
        {Target}   {version}     {image id}   {when}   xxx GB

#
# load したイメージに latest タグを振っておく
# docker-compose では latest イメージを使うように書いているから
#
docker tag {Target}:{version} {Target}:latest 

＃
# docker-compose で起動
#
docker-compose up -d
 ```

 ## デプロイ環境 (バージョンアップ時)
 ```
#
# docker-compose を停止
#
docker-compose down

#
# バージョンアップした docker イメージをローカル環境にロード
#
gzip -d {TargetImage}.tar.gz -c | docker load

    docker image ls
        {Target}   {version}     {image id}   {when}   xxx GB

#
# load したイメージに latest タグを振っておく
# これで今ロードしたイメージが latest になります
# (旧イメージを削除するなら docker rmi などで)
#
docker tag {Target}:{version} {Target}:latest 

＃
# docker-compose で起動
#
docker-compose up -d
 ```


# おわりに
 　全くなにを言ってるんだか、当たり前田のクラッカーだろうが。。。
  
 　なんて思われるでしょうが、それはきっと「**バージョンアップまで考えたデプロイ**」を経験しているからで、知らない人だっているでしょうから。

 　だって デバッグでは  docker-compse.yml では開発ソース環境一式を volume でホストマウントして、Visual Studio Code の リモート機能使って、開発してますよね。 yml は image ではなく build を使って。
  
　それをそのまま環境に置けば、自身が開発したコードの修正だけなら、ホスト上の開発コードをバージョンアップすればいいだけですから。 git 管理なら git  pull だけですし。

　この記事がお役に立つのはごくごく一部の人だと思いますが、その人達にとってはきっとお役に立つと思うので記事にしておきました！
AOP(アスペクト指向プログラミング)

## AOP
プログラムを中心的関心事と横断的関心事に分ける考え方のこと。
**中心的関心事:** 実現したいプログラム
**横断的関心事:** 中心的関心事に付随するプログラム

**(例)**
データベースへアクセスしてデータを取得する処理を例に挙げると、データベースへアクセスする処理が「中心的関心事」、例外処理が「横断的関心事」。
Spring Frameworkの「インターセプト」をいう仕組みを使うと、中心的関心事と横断的関心事を分離して、横断的関心事を中心的関心事に挿入しているように見せることができる。
![スクリーンショット 2024-08-24 10.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551832/9de1d05a-708e-bf63-efb2-d549e4a425aa.png)
**Advice:** 横断的関心事のメソッド
**Aspect:** Adviceをまとめたクラス
AOPを利用すると、クラスAからクラスBのメソッドXを呼び出しているだけに見える(実際はAspectも呼び出している)

## Pointcut式
Adviceを作成する場合、Adviceをどのクラスのどのメソッドに挿入するか条件で指定できる。
Pointcut式は数種類あるがexecutionについては以下
```java
// 構文
execution(戻り値の型　パッケージ.クラス.メソッド(引数))
// 使用例
// SampleServiceクラスの全てのメソッドに適用
execution(*com.sample.service.SampleService.*(..))
```
## 使ってみる
### AOPクラス
Adviceを記述するクラスには@Aspectを付与する。
@Componentについては1つ前の記事を参照
```java
@Aspect
@Component
public class Aspect {}
```

### Advice
中心的関心事が実行される前に呼び出すAdviceを作成する。
@Beforeを付与すると、指定した中心的関心事であるメソッドが実行される前に呼び出すことができる。
パッケージ「com.sample.demo.chapter03.used」のクラス名が「Cat」で終わるクラスの、全てのメソッドを指定している。
つまり、パッケージ「com.sample.demo.chapter03.used」のクラス名が「Cat」で終わるクラスの、全てのメソッドが実行される前にbeforeAdviceが実行される。

```java
@Aspect
@Component
public class Aspect {

  @Before("execution(*com.sample.demo.chapter03.used.*Cat.*(..))")
  public void beforeAdvice(JoinPoint joinPoint) {
    System.out.println("Advice実行");
  }
}

```
### 中心的関心事
```java
public class Main() {

  public void callCrying() {
    //中心的関心事であるcryingメソッドを呼び出す
    BlackCat cat = new BlackCat();
    cat.crying();
  }
}

public class BlackCat {
  public void crying() {
    System.out.println("にゃあ");
  }
}
```
BlackCatクラスのcryingメソッドが実行されると以下が出力。
@Beforeを付与しているのでcryingメソッド(中心的関心事)が実行される前にbeforeAdvice(横断的関心事)が実行される。
```
Advice実行
にゃあ
```
このように横断的関心事を中心的関心事に注入することができるので、中心的関心事を呼び出しているだけに見えても、実際には横断的関心事も呼び出している。これがAOPの仕組み。

## その他のアノテーション
@Before以外にもアノテーションがある
|アノテーション  |説明  |
|---|---|
|@AfterReturning  |中心的関心事が正常に実行された後に横断的関心事を実行する  |
|@AfterThrowing  |中心的関心事で例外がスローされた後に横断的関心事を実行する|
|@After|中心的関心事が実行された後に横断的関心事を実行する(正常終了・例外終了など問わず)|
|@Around|中心的関心事の呼び出し前後で横断的関心事を実行する|

## AOPの考え方
多数のクラスに対して共通して必要となる処理が「横断的関心事」になる。その多数のクラス１つ１つに対して地道に横断的関心事を実装するのは効率的でない。横断的関心事を多数のクラスに自動的に挿入でき、必要なくなれば自動的に削除できる、それがAOPである。
k8s Docker 用語理解

## Pod
k8sでアプリケーションを動かすための最小単位です。

podの中には、アプリケーションを動かす「コンテナ」が入っています。
コンテナは以下をまとめたものです。
>・アプリケーション(コード)
・その動作に必要なもの（ライブラリや設定ファイル(config.yaml .env)）

## クラスタ
たくさんのコンピュータ（またはサーバー）が集まって
１つの大きなコンピュータのように動く仕組みのこと。

>複数のコンピュータが集まって1つのコンピュータっぽく振る舞っているシステム

## ノード
そのクラスタを１つ１つのコンピュータやサーバーのことです。
クラスタの中にはたくさんのノードがあって、それぞれが役割をもって仕事をします。
ノードは、クラスタの中で実際にアプリケーションを動かす場所です。po
TVTestをPCリモコン (BUFFALO製DT-OP-RC) で操作する

# TVTestをリモコンで操作したい
TVTestをリモコンで操作するため、家に転がっていたBUFFALO製DT-OP-RCを活用します。

DT-OP-RCはボタンを押すとそのボタンに対応したショートカットキーを送信するだけのモノなので、比較的簡単にTVTestで使うことができました。
[TVTest]→[設定]→[キー割り当て]から対応するショートカットを登録してあげることで使用できます。ボタンに対応したキーの割当表は以下の通りとなります。

## DT-OP-RCのキー割当
その昔、某大手掲示板にキー割当をあげてくださっている方がいらっしゃったのですが、すでに消えてしまっているようなので新たに作成しました。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831804/4d8c8cd7-8c70-1e31-3167-c4ca0f3bb1b4.png)

DT-OP-RCの特徴として、リモコンの信号送信部が2カ所あるため割と感度よく反応してくれます。また、データ放送用のボタンも一通り揃っているので、TVTDataBroadcastingWV2プラグインと併用することでより家庭用テレビの操作感に近づけることが可能です。

最後に、参考までに私の使っているTVTestでの設定です。
以下設定で一通りデータ放送や字幕etcがリモコンで動作することを確認しています。
![2024-08-24_110218.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831804/3593fc87-189b-926e-bc05-09c4252d44ee.jpeg)