OmniAICreator/Qiita-1.07M huggingface dataset:
【練習】ブラウザで作った文字列コピーツール

## JavaScriptで簡単なツールを作る練習

ボタンを押すとクリップボードに文字列がコピーされるツールです。
文字列を選択してからコピーする、を繰り返す時に便利なツールです。

``` html
<!doctype html>
<html lang="ja">
	<head>
		<meta charset="utf-8">
		<title>copyToClipBoard</title>
	</head>
	<style>
		section{
			width: 500px;
			margin: 10px;
			padding: 10px;
			color: #333;
			background-color: #ddd;
			border-radius: 10px;
		}
		p{
			margin: 5px;
		}
		h2{
			margin: 0;
		}
		.search{
			width: 50px;
			padding: 2.5px 5px;
			color: blue;
			border: solid 1px #fff;
			border-radius: 10px;
		}
		.replace{
			width: 50px;
			padding: 2.5px 5px;
			color: green;
			border: solid 1px #fff;
			border-radius: 10px;
		}
	</style>
	<body>
		<h1></h1>
		<section>
			<h2 class="search">検索</h2>
			<article>
				<h3>条件</h3>
				<p class="copyString">A|B|C</p>
				<button class="copyButton">Copy</button>
			</article>
		</section>
		<section>
			<h2 class="replace">置換</h2>
			<article>
				<h3>置換前</h3>
				<p class="copyString">\s*\*\s*/\s*$</p>
				<button class="copyButton">Copy</button>
			</article>
			<article>
				<h3>置換後</h3>
				<p class="copyString"></p>
				<button class="copyButton">Copy</button>
			</article>
		</section>
		<script>
			function copyToClipBoard(){
				const sections = document.querySelectorAll(`section`);
				for(const section of sections){
					const articles = document.querySelectorAll(`article`);
					for(const article of articles){
						const copyString = article.getElementsByClassName(`copyString`)[0];
						const copyButton = article.getElementsByClassName(`copyButton`)[0];
						copyButton.addEventListener(`click`, () => {
							navigator.clipboard.writeText(copyString.innerHTML);
						});
					}
				}
			}
			
			copyToClipBoard();
		</script>
	</body>
</html>
```

## 見た目

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2115724/e7133a11-6fb1-21f2-8c68-896048dd5db2.png)


## 改良した方が良いところ

- ボタンを押すと「コピーされました」というチップを表示したい。
- むしろマクロ化した方が速い。
ITエンジニアに向いてないと悩んでる？→そんなことない！！

エンジニアとして働いていて「自分はエンジニアに向いていないのではないか」と悩んだことはありませんか？実は私も、新人エンジニアからそんな相談をよく受けます。<strong>しかしその悩みはエンジニアのほとんどが感じており、「自分はエンジニアに向いている」と自信を持って仕事をしている人はほとんどいません。</strong>

この記事ではエンジニアの私が、エンジニアの「自分エンジニアに向いてないかも」という悩みについて、経験に基づいたアドバイスをさせていただきます。本当にエンジニアが向いていない人や対処法についてご紹介していきますので、ぜひ最後までご覧ください。

<iframe width="560" height="315" src="https://www.youtube.com/embed/Lk667vKcVqo?si=rV3GPSO7W8_b58b0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

## ITエンジニアに向いていない人の特徴

![Characteristics-of-unsuitable-IT-engineers.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784196/7af45214-7f08-e316-d6e0-3dab80b9688f.jpeg)


ここでは、エンジニアに向いていない人の特徴について紹介します。

- 論理的思考力や問題解決能力が苦手
- 新しい技術を学ぶことに抵抗がある
- 人とコミュニケーションを取ることが苦手

[>> 向いてない人の特徴詳細はコチラ！](https://taishi-official.com/2024/05/09/2254/#toc2)

ただここで紹介することは、どんなベテランエンジニアであったとしても多少はあるものです。<strong>極端にこれらに対して苦手意識がなければ、経験を積んでいくことで慣れ、徐々にできるようになっていきます。</strong>

## エンジニアの仕事が向いていないと感じたときの対処

![What-to-do-when-you-feel-like-you're-not-cut-out-to-be-engineer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784196/fce82490-8c01-d3c2-1467-52be97704d7c.jpeg)


ITエンジニアに向いていないと感じた時の対処法として、以下のようなことが考えられます。

- 具体的な理由を分析する
- 職種を変えてみる

[>> 向いてないと感じたときの対処詳細はコチラ！](https://taishi-official.com/2024/01/21/1500/)

## まとめ
今回はITエンジニアに向いていない人の特徴とその対処法について解説しました。おそらく余程才能にあふれるエンジニアでなければ、**誰しもが同様に「自分はITエンジニアに向いていない」と感じてしまう**ものです。

私もエンジニアとして働きながらいろいろな人を見てきましたが本当に向いていない人は、そもそもプログラミング自体が苦痛で悩む前にIT業界から去っていきます。<strong>エンジニアとしてお仕事ができて、会社に貢献してお給料がいただけている時点で、むしろかなり向いている方だと言えます。</strong>向いていないと感じさせるのは仕事内容であったり、人間関係が原因であることが大半だと思われるので、ご自身を卑下せずに自信を持っていただけたらと思います。

### おまけ

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

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

<br>

<strong>＼Follow me／</strong>

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

<br>

最後にいいねお願いします:thumbsup:
Node.jsでCLIツールを作ろう！〜Commanderを使ったコマンド実装パターン〜

# はじめに
Node.jsを使ってCLIツールを開発する際に便利なのが、```Commander```ライブラリです。Commanderを使うと、コマンドラインからの入力を簡単に解析し、適切なアクションを実行することができます。
今回は、Commanderを使ったコマンド実装のパターンを紹介します。このパターンに従うことで、CLIツールに新しいコマンドを追加するのが容易になります。

# プロジェクトの構成
プロジェクトのディレクトリ構成は以下のようになります。
```
src/
  ├── commands/
  │   ├── server.ts
  │   └── ・・・
  └── index.ts
```
```src/commands/```: 各コマンドの実装を格納するディレクトリ
```src/index.ts```: コマンドを登録し、CLIツールのエントリーポイントとなるファイル

# コマンドの実装
まずは、```src/commands/server.ts```を作成し、serveコマンドを実装します。

```ts:server.ts
import { Command } from 'commander';

export const serveCommand = new Command()
  .command('serve')
  .description('Open a file for editing')
  .action(() => {
    console.log('Getting ready to serve a file!');
  });
```

Commandをインポートし、新しいコマンドインスタンスを作成
.command('serve')で、コマンド名を指定
.description('Open a file for editing')で、コマンドの説明を追加
.action(() => { ... })で、コマンドが実行された際のアクションを定義

# コマンドの登録
次に、```src/index.ts```を編集し、作成したコマンドを登録します。
```ts:index:ts
import { program } from 'commander';
import { serveCommand } from './commands/server';

program.addCommand(serveCommand);

program.parse(process.argv);
```

Commanderからprogramをインポート
作成したserveCommandをインポート
```program.addCommand(serveCommand)```で、serveCommandを登録
```program.parse(process.argv)```で、コマンドラインの引数を解析

# 型定義ファイルのインストール
TypeScriptを使用している場合、Node.jsの型定義ファイルをインストールする必要があります。
```bash:bash
lerna add @types/node --dev --scope=cli
```
```lerna add```を使って、```@types/node```をインストール
```--dev```フラグを付けて、開発依存関係として追加
```--scope=cli```で、cliパッケージにのみインストール

# CLIツールの実行
コンパイル後、生成された```dist/index.js```を実行することで、CLIツールを試すことができます。
```bash:bash
node packages/dist/index.js serve
```
serveコマンドを実行すると、```Getting ready to serve a file!```というメッセージが表示されます。
また、```--help```オプションを付けて実行すると、利用可能なコマンドとその説明が表示されます。
```bash:bash
node packages/dist/index.js --help
```

# おわりに
以上が、Commanderを使ったコマンド実装のパターンです。このパターンに従うことで、CLIツールに新しいコマンドを追加するのが容易になります。
今回は基本的な実装のみを紹介しましたが、実際のCLIツールではもっと複雑な処理が必要になることもあるでしょう。しかし、このパターンを理解していれば、それらの処理を適切な場所に追加していくことができます。
ぜひ、自分のCLIツールの開発に活用してみてください！

# 参考
https://www.npmjs.com/package/commander
sortの+POS1 -POS2と-k POS1,POS2 の違い

# まとめ
sortの+POS1 -POS2 オプションと-k POS1,POS2 は同じでないから注意。
-kのPOS1は１足す必要あるけど、POS2は「通常」そのままだ。

#  簡単な例
```
$ cat  sort2.txt
22 33 11
11 33 22
11 22 11
```
これを第2列でソートする。古いオプションだと以下。
```
$ sort +1 -2 test.txt
11 22 11
11 33 22
22 33 11
```

新しいオプションだと以下が正解。
```
sort -k 2,2 test.txt
11 22 11
11 33 22
22 33 11
```

つい、-k 2,3とやってしまうと結果が異なり悩む。
私がそこでハマりました。
```
$ sort -k 2,3 test.txt
11 22 11
22 33 11
11 33 22
```

# はまりどころ
古いオプションは0オリジンだけど、新しい-kオプションでは1オリジン。
だから sort +1 -2をsort -k 2,3としてしまいそうになる。

例えば以下の記事を見ると先頭位置を0⇒1考慮したらOKと読める。
そう思ったら、嵌ります。
https://xtech.nikkei.com/it/article/COLUMN/20060227/230887/

# pos2は+1しなくていいのはなぜ？
身も蓋もない言い方だけど仕様。
例えば以下。
https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html


On systems not conforming to POSIX 1003.1-2001, sort supports a traditional origin-zero syntax ‘+pos1 [-pos2]’ for specifying sort keys. The traditional command ‘sort +a.x -b.y’ is equivalent to ‘sort -k a+1.x+1,b’ if y is ‘0’ or absent, otherwise it is equivalent to ‘sort -k a+1.x+1,b+1.y’.

xとyは列の中での文字位置だけど通常は指定しないでしょうから、
-kだと「sort -k a+1.x+1,b」側になりますね。
aは+1だけど、bはそのまま。

# 追記
コメントで教えて頂いた、--debugオプション。これ知りませんでした。
ものすごく便利。
実は、+POS1 -POS2オプションから-k POS1,POS2オプションの書き換えで結果が異なり、かなり悩んだのですが、--debugで見れば瞬殺ですね。ありがとうございます！！

```
sort +1 -2 test.txt --debug
11 22 11
  ___
________
11 33 22
  ___
________
22 33 11
  ___
________
```
古いオプションだと2列目だけがキーだけど、
-k 2,3 だと2列目と3列目がキーになっているのがわかる。
```
sort -k 2,3 test.txt --debug
11 22 11
  ______
________
22 33 11
  ______
________
11 33 22
  ______
________
```

あと、
「sort: leading blanks are significant in key 1; consider also specifying 'b'」
とも言われるが、１行目の22の前の空白もキーに入っている点に注意。

さらに、sort -k 2,2 test.txtなどで横棒の線が
```
  ______
________
```
と2本あるけど、これは最初に2列目でソートするが33の部分は2レコード目と3レコード目が同じになるので、最後に全体をみて2レコード目と3レコード目の順序を決めるという意味。
この機能を「last-resort comparison」と言う（そうです）。

sortって古くからあるコマンドでなめていたけど、今回、ちょっと調べただけでも、キーの扱いとか列の区切り空白とかロケールとの影響とか、さまざまな事を知りました。本当に奥が深い。

#  さらに追記

いろいろと勉強になったページ
https://qiita.com/ko1nksm/items/af8f6305944a3920b925

日本語で+POS1 -POS2と-k POS1,POS2 の違いまで書かれているページ
https://kazmax.zpp.jp/cmd/s/sort.1.html
ボタンクリックで「あっち向いてホイ」を作る

## はじめに
今回は、ボタンクリックのみの操作の「あっち向いてホイ」を作ったので、コードを紹介していきます。

（▼同様の記事をnoteでも公開しています）
制作の振り返り：https://note.com/shinbomizuki/n/n2d29ef3c489a
コード紹介：https://note.com/shinbomizuki/n/n1046763ffda5

動作環境は
・**macOS**
・**Unity 2021.3.0f1**
です。

よろしくお願いします。

## 用意したもの

・背景
・キャラクターの表情差分（体と分けて用意したので、容量を小さくできてる…はずです）
・キャラクターの体
・上下左右の矢印ボタン
・勝ちか負けかによって表示するパネル

## スクリプト

構造としては、
**①ランダムで配列から数字を取り出す**
**②キャラクターが上下左右を向いた画像を用意しているので、①で取り出した数字に対応する画像を表示する**
**③表示された画像とプレイヤーが予想した方向が同じだったら勝利、異なっていたら敗北と表示する**
としました。

スクリプトです。

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Game : MonoBehaviour
{
    //ランダム
    public GameObject[] Train;
    private int number;

    public GameObject Normal;
    public GameObject Win;
    public GameObject Lose;

    //2度押し禁止
    private bool firstPush = false;

//ボタンがクリックされたらメソッド
    public void Down()
    {
        if (!firstPush)
          {
            firstPush = true;
            Normal.gameObject.SetActive(false);
            //顔の向きをランダムに表示する
            number = Random.Range (0, Train.Length);
            Instantiate(Train[number],transform.position,transform.rotation);
            //同じ向きだったら勝利
            if (number == 0){
                Win.gameObject.SetActive(true);
            } else {
                Lose.gameObject.SetActive(true);
            }
        }
    }
```

長くなってしまうので省略しましたが、この下に続けてnumberが1〜3の時の処理も書いています。
（少し前に作ったゲームなので、特に命名規則がぐちゃぐちゃで悔しい…）

## おわりに
最後まで見ていただき、ありがとうございました。
いろいろな機能が作れるよう、これからも頑張って勉強を続けていこうと思います。
では、また次回の記事でお会いしましょう。
毎日ABC day2【c++】ABC344 A-E問題解説【ACコード付き】

# AtCoder Beginner Contest 344
毎日ABC2日目。

https://atcoder.jp/contests/abc344

## A - Spoiler
`|`2つでで区切られている文字列が渡されるので、`|`の間の文字列を消去し、端の文字列同士を結合したものを出力する問題。Pythonだとめちゃシンプルにsplit関数で実装できるらしい

```cpp
int main()
{
	string S;
	cin >> S;
	int x = S.find("|");
	int y = S.rfind("|");
	cout << S.substr(0, x) + S.substr(y + 1) << endl;
	return 0;
}
```

Pythonだと何とこれだけ！！（公式解説から引用）
```py
S = input()
a, b, c = S.split('|')
print(a+c)
```

## B - Delimiter
$N$個の整数が与えられるので、それらを逆順に出力する問題。$N$が問題文に与えられない代わりに、$A_{N}$が0であり、$A_{N}$までは0でないことが保証される。

```cpp
int A[109];

int main()
{
	int i = 0;
	while (true)
	{
		cin >> A[i];
		if (A[i] == 0)
			break;
		i++;
	}
	while (i >= 0)
	{
		cout << A[i] << endl;
		i--;
	}
}
```

## C - A+B+C
整数の集まりが３つ与えられる。それぞれの集まりから1つずつ足した数で、$X_{i}$を表すことができるか判定する問題。今回$X_{i}$が最大で$10^8$個与えられるので、毎回足してみるのではなく、可能性のある数字をリストアップしておく。

自分の実装ではvectorをソートしたが、今回の問題は重複は無視して良いので、setで実装した方が計算料が抑えられたと思う。

```cpp
int N,M,L,Q;
int A[109];
int B[109];
int C[109];
int X[200009];
int AB[10009];
vector<int> ABC;

int main()
{
	// 入力
	cin	>> N;
	for (int i = 0; i < N; i++) cin >> A[i];
	cin >> M;
	for (int i = 0; i < M; i++) cin >> B[i];
	cin >> L;
	for (int i = 0; i < L; i++) cin >> C[i];
	cin >> Q;
	for (int i = 0; i < Q; i++) cin >> X[i];
	// A, Bからひとつずつ取ってできる数を列挙
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < M; j++)
		{
			for (int k = 0; k < L; k++) ABC.push_back(A[i] + B[j] + C[k]);
		}
	}
	// ソート
	sort(ABC.begin(), ABC.end());
	int min = ABC[0];
	int max = ABC[ABC.size() - 1];
	for (int i = 0; i < Q; i++)
	{
		if (X[i] < min || max < X[i])
		{
			cout << "No" << endl;
			continue;
		}
		auto itr = lower_bound(ABC.begin(), ABC.end(), X[i]);
		if (*itr == X[i]) cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	return 0;
}
```
エンジニアとしてフルリモートワークで8年生き残る技術

こんにちは。[吉田智哉](https://twitter.com/tomoya_y0shida)です。
岩手県盛岡市に住みながらエンジニアとしてフルリモートワークで東京の開発案件を請けてます。
気が付くとこの働き方で8年間も経過していました。
8年生き延びることができたので、そのコツをシェアしたいと思います。

## その日のコミットはdraftのpull requestとして出す

エンジニアは成果物が全てです。
いくら一生懸命働いていたとしても、成果物、つまりコードがなければその日働いていたとしても
成果として認められません。
チームメンバーやリーダーに対してちゃんと働いていることをアピールするために、
その日のコミットはその日のうちにpull requestとして出すようにしています。
作業が途中の場合はdraftのpull requestにしています。
pull requestとして出せない調査系のタスクの場合は
調査した記録をドキュメントとして残しておいて、
他の人も閲覧できる状態にしておきます。

## わかりやすい文章を書くように心がける

リモートワークは基本的にチャットを用いて文字のやりとりです。
通常の会話のように身振り手振りなどで情報を補うことができないので、
文字だけで伝わるようなわかりやすい文章を書くように心がけています。

## コミュニケーションの手段にこだわらない

チャットを用いての文字のやりとりが基本ですが、
写真やスクリーンショット、スクリーンキャプチャ、図解など
場合によっては文字以外の手段も積極的に取り入れるようにしています。
自分の考えを伝えることが一番なので、文字だけなど手段にはこだわらないように
しています。
口頭で確認したい場合は、ビデオ通話を用いるのもよいでしょう。

## ビデオ通話の時は結論やネクストアクションをチャットに記入する

口頭でやりとりできるビデオ通話はとても便利ですが、録画しない限り記録に残らないことが
デメリットです。

ビデオ通話の場合は、
認識の齟齬がないか確認ができる、社内にも話した内容が共有できるため、
結論やネクストアクションをチャットに記入しておくようにしています。

## 冷たい印象を与えないように絵文字を多用する

チャットの文字だけのやりとりだと冷たい印象を与えてしまいがちです。
「わかりました。」よりも「わかりました💪」のように文末に絵文字を入れて、
冷たい印象を与えないように気を付けています。

## 常に最新技術を学んで試してみる

気になる新刊は購入して読むようにしています。
（経費で落とせるし）
本のすべてを読もうとせずに、目次をはじめに読んで気になるところだけを先に読むことで
「買ったけどまったく読んでいない」という状態をなくすことができます。

## アウトプットする

正社員として転職やフリーランスで案件を変えるときに、面接官は候補者のSNSやブログ、githubの
リポジトリなどを案外見ています。

最近の面談でも「githubでよくアウトプットしていますね💪」とgithubのアウトプットを評価してもらえました。
わたしはいろいろな技術を試したら、githubにリポジトリとして保存するようにしているのですが、それを評価してもらえたようです。
githubに限らず、日ごろの学習や試したことを評価してもらえるように見せられるものはどんどんブログや技術記事として
公開すると転職活動時に役立つと思います。

## 毎日の業務の記録を残しておく

毎日の業務でやったことや感じたことの記録は後でいろいろと使えるので、
その日のうちに記録をとっておきます。
今だとnotionで日記をとるのがおすすめです。
公開できるものはブログなどで公開してしまうのもアピールになります。

## 魅力的な経歴、プロフィールを転職サイトに書く

転職サイトのプロフィールには魅力的な経歴を書きましょう。
その時に役に立つのが毎日の業務の記録です。
業務の記録をとっておけば、その中からアピールできるものを抜き出して書くだけです。
書き方のポイントは検索結果に引っかかるようにキーワードを意識することです。
たとえばフィンテックやECサイトの仕事を獲得したければ、経歴の中に書いておくとよいでしょう。
またパフォーマンスチューニングをした場合は
「3時間のバッチを10分以下に短縮した実績あり」など具体的な数字を書くとよいと思います。

以下に参考までに私のwantedlyのプロフィールのリンクを貼っておきます。

[https://www.wantedly.com/id/tomoya_yoshida_l](https://www.wantedly.com/id/tomoya_yoshida_l)

このプロフィールでありがたいことに毎月1件はスカウトをもらうことができます。

## まとめ

8年もエンジニアとしてフルリモートワークできるのはありがたいことです。
常に技術を高めていくことが求められますが、その分の対価をしっかりもらえるエンジニアの
世界はとてもやりがいがあります。
エンジニアはどこに住んでいてもできるので、地元という好きな場所で働くこともできます。
これからも試行錯誤しながら、これから先の10年、20年を生き残っていきたいと思います。
ろうとるがPythonを扱う、、（その23：ScapyでDNSフィルタリング）

# ScapyでDNSフィルタリング
Scapyでネットワークブリッジを構築し、ブリッジ内でDNSフィルタリングを実施してみた。

## ネットワーク
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/6244f8c8-6482-c880-dfe4-ede718b51a72.png)
ubuntu上にScapyによるネットワークブリッジを設け、そこでDNSフィルタリングを行う。ClientからはRouterをとおしてインターネットへアクセスする。（なお、ClientはRouter上で動作しているDHCPサーバーからIPアドレスを取得する。）

## DNSフィルタリング
フィルタリングとして、特定ドメインをブロックするもの。いわゆるブラックリストを作成し、Webアクセスなどが行えないよう制御する。

## ソースコード
### ブラックリスト
”blacklist.txt”というファイルにアクセスを許可しないドメインを記載する。なお、”.”（ピリオド）ではじまる場合、ワイルドカード的に扱うこととした。
```shell:blacklist.txt
yahoo.com
.zm
www.bbc.co.uk
```
上記の２行目では、”www.abc.zm”や”xdu.zm”もマッチ（適用）するものとする。”.”（ピリオド）ではじまらない場合は、完全一致した場合のみ適用する。

### コード本体
```python:dns_filter.py
from scapy.all import *
import datetime

blk_list = []

def cb_filter(p):
    found = 0
    if p.haslayer(DNS):
        dns = p.getlayer(DNS)
        qname = dns.qd.qname
        #print(qname.decode('utf-8'))
        chk_domain = qname.decode('utf-8').rstrip('.')
        for blk_domain in blk_list:
            if blk_domain.startswith('.'):
                if chk_domain.endswith(blk_domain):
                    found = 1
                    break
            else:
                if chk_domain == blk_domain:
                    found = 1
                    break
    if found == 1:
        now = datetime.datetime.now()
        d = now.strftime('%Y/%m/%d-%H:%M:%S')
        msg = d + ' ' + chk_domain + ' is dropped.'
        print(msg)
        msg += '\n'
        flog.write(msg)
        return False
    else:
        return True

with open('blacklist.txt') as f:
  for line in f:
    blk_list.append(line.rstrip())

flog = open('dns.log', 'a')

bridge_and_sniff('enp3s0', 'enp1s0f0', xfrm12=cb_filter, xfrm21=cb_filter)

#do not call flog.close()
```
- blk_list: ブロックするドメインのリスト
- cb_filter: ブリッジ時にCallされる関数
    - DNSパケットのみを対象
    - ブリッジを通過するDNSのドメイン名を取得（最後のピリオド”.”削除）
    - ブロックするドメイン名がピリオド”.”で始まっている場合、取得したドメイン名が後方一致するかチェック
    - ピリオド”.”で始まっていない場合、取得したドメイン名が完全一致するかチェック
    - 一致した場合、コンソール表示およびログへの書き込み
    - 一致した場合、Trueを返す（転送する）
    - 一致しない場合、Falseを返す（転送しない）
- ブラックリストファイル（blacklist.txt）に格納されているドメイン名をblk_listに格納
- ログファイル（dns.log）をオープン
- bridge_and_sniff(): ２つのネットワークI/F（"enp3s0","enp1s0f0"）のブリッジ化およびブリッジ時にCallされる関数（cb_filter）の定義

## 検証
ほぼ自明なので、クライアントの状況は省略。上記コードで記載したログファイル（一部）は下記のとおりとなる。
```shell:access.log

2023/12/31-14:37:05 www.bbc.co.uk is dropped.
2023/12/31-14:37:05 www.bbc.co.uk is dropped.
2023/12/31-14:37:14 www.cabinet.gov.zm is dropped.
2023/12/31-14:37:14 www.cabinet.gov.zm is dropped.

```

## 終わりに
パフォーマンス的には今ひとつかもしれない。とにかく、Scapyは便利である。関連して、「[ろうとるがPythonを扱う、、（その20：Scapyで改ざん）](https://qiita.com/infinite1oop/items/9ee5e979c31b2028db5d)」でも一部実施したが、本格的なSpoofingもできそう（気が向いたらトライしてみる）。
Test Classのまとめ



+ [Test Apex Class でのToo many SOQL queries: 101エラー](https://qiita.com/Keiji_otsubo/items/22b62c180c72eb739dae)
+ [よく分からんError Apex Specialist - Test automation logic challenge 4](https://qiita.com/Keiji_otsubo/items/7416b417f973f66e7d3e)
+ [テストスクリプトの例](https://qiita.com/Keiji_otsubo/items/69d196cf02dc7d3663b6)
+ [取引先の所有者が変更された場合に取引責任者の所有者も変更する](https://qiita.com/Keiji_otsubo/items/5e4c0aeb12f11d6785b7)
+ [Batch process which periodically archive SObjects to Big Objects](https://qiita.com/Keiji_otsubo/items/5ab78b06c91b8069249d)
+ [モックの作成が上手くいかず、Apexテストのカバレッジが上がりません。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007clY7J)
+ [少々手を抜いたら思わぬエラーで余計に時間がかかってしまいました。](https://qiita.com/Keiji_otsubo/items/ac5c93158d3074d2587d)
Azure Functions でパブリックプレビューの Flex Consumption を Azure CLI で試してみた

新しい Azure Functions ホスティングプランの Flex Consumption が発表されました。パブリックプレビューですが、既に Azure CLI でも使用できるようなので試してみました。

## 動作確認バージョン

```bash:bash
$ dotnet --version
8.0.100

$ func --version
4.0.5801

$ az version
{
  "azure-cli": "2.61.0",
  "azure-cli-core": "2.61.0",
  "azure-cli-telemetry": "1.1.0",
  "extensions": {}
}
```

## 検証用の Azure Functions Flex Consumption を作成

```bash:bash
prefix=mnrfna
region=eastus

az group create \
  --name ${prefix}-rg \
  --location $region

az storage account create \
  --name ${prefix}sa \
  --resource-group ${prefix}-rg \
  --sku Standard_LRS

az functionapp create \
  --name ${prefix} \
  --resource-group ${prefix}-rg \
  --flexconsumption-location $region \
  --instance-memory 2048 \
  --runtime dotnet-isolated \
  --storage-account ${prefix}sa \
  --disable-app-insights \
  --https-only \
  --assign-identity
```

## Azure ポータルで Flex Consumption を確認

![functions-flex-consumption-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/58745f96-6e48-dc13-7a6b-049363093876.png)

## ローカルで検証用の Functions アプリを作成

```bash:bash
func init $prefix --worker-runtime dotnet-isolated --target-framework net8.0

cd $prefix

func new --name example --template HttpTrigger --authlevel anonymous

func start
```

## 検証用 Functions アプリをデプロイ

```bash:bash
func azure functionapp publish $prefix
```

`Can't determine Project to build. Expected 1 .csproj or .fsproj but found 2` と表示されたので、ローカル環境をクリーンにしてからデプロイしなおしました。

```bash:bash
dotnet clean

func azure functionapp publish $prefix
```

## 動作確認

```bash:bash
$ curl https://$prefix.azurewebsites.net/api/example

Welcome to Azure Functions!
```

## 後片付け

```bash:bash
az group delete \
  --name ${prefix}-rg \
  --yes
```

## 参考

https://techcommunity.microsoft.com/t5/apps-on-azure-blog/azure-functions-microsoft-build-2024-update/ba-p/4146471

https://azure.microsoft.com/en-us/updates/public-preview-azure-functions-brings-new-flexibility-with-azure-functions-flex-consumption/

https://learn.microsoft.com/ja-jp/azure/azure-functions/flex-consumption-plan

https://learn.microsoft.com/ja-jp/cli/azure/functionapp?view=azure-cli-latest#az-functionapp-create-examples
chocott-backstageを試す

# backstageを試す
- APCさんから提供されているコンテナイメージを使ってローカル環境でサクッと試してみる

- https://github.com/ap-communications/chocott-backstage

# デフォルトからの変更点
- 事例あり、M1 mac仕様に以下の点を変更
    - https://zenn.dev/daylight55/scraps/04af726a505e0f
【Salesforce】Lightning Web Components

Lightning Web Components（ライトニングウェブコンポーネント）について、記事にします。

# Lightning Web Componentsって何？
Lightning Web Components（LWC）は、Salesforceが作った、ウェブページを作るためのツールです。ウェブサイトやアプリケーションに使うパーツを作るためのものです。

## どうして使うのか？
LWCを使うと、ウェブページをより速く、より簡単に、そして効率よく作ることができます。
例えば、以下のような理由があります。

- スピード
LWCは、ページを高速で表示するのに適しています。
- 再利用性
一度作ったコンポーネントは、他のページでも簡単に使い回すことができます。
- 最新技術
LWCは、最新のウェブ技術を使って作られているので、最新の機能を利用できます。

## 具体例
LWCを使ってウェブページを作るには、主に以下のような作業を行います。

Salesforce に関する知識と、HTML、JavaScript、CSS の経験を用いて、Salesforceアプリケーションを作成できます。
また、これらの標準を使用しつつ、Salesforce 組織向けのコンポーネントを作成すると同時に、既存の Aura コンポーネントとの互換性を維持します。

例
例えば、簡単な「Hello, World」というメッセージを表示するコンポーネントを作ってみましょう。

HTMLファイル（helloWorld.html:

```HTML
<template>
  <input value={message}></input>
</template>
```

CSSファイル（helloWorld.css:
```CSS
input {
  color: blue;
}
```

JavaScriptファイル（helloWorld.js）:

```Javascript
import { LightningElement } from 'lwc'; 
export default class App extends LightningElement { 
  message = 'Hello World'; 
}
```

このようにして、LWCを使ってシンプルなWebコンポーネントを作成できました。

# まとめ
Lightning Web Componentsは、ウェブページを効率よく作成するためのツールで、簡単なコンポーネント作成から、Apexと組み合わせたアプリケーション開発まで幅広く使われています。

個人的に、SalesforceとWebの技術のいいとこ取りできるのが嬉しいです。
HTML、JavaScript、CSSの基本を知っていると、LWCを使う際に役立つと思います！


参考

https://help.salesforce.com/s/articleView?id=release-notes.rn_lc.htm&release=218&type=5

https://trailhead.salesforce.com/ja/content/learn/modules/lightning-web-components-basics/discover-lightning-web-components
SquarespaceでDNS recordが Custom record not savedとなり追加できない

## Error

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7059/27f1d3bd-5887-961a-5c0c-958565715383.png)

## 解決策

一回ログアウトしてからもう一度ログインして試す

https://forum.squarespace.com/topic/263037-custom-dns-record-cannot-be-saved/

![Screenshot 2024-05-25 at 7.46.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7059/e4e996e7-f428-19e6-cf2f-5dc0344806d0.png)
SalesforceのName項目について

## Name項目とは
Salesforceの全てのオブジェクトは、API参照名 =「Name」の項目を必ず持っています。例えば、取引先オブジェクトの「取引先名」や、商談オブジェクトの「商談名」はName項目になります。
カスタムオブジェクトもName項目は必ず持っており、新規カスタムオブジェクト作成画面で定義します。

##### 画像：新規カスタムオブジェクト作成画面のName項目設定箇所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674790/eacf637e-4d43-34f9-248d-e2f0a8bd05b0.png)
設定項目はレコード名とデータ型のみです。ちなみにこれらは後で変更することも可能です。（データ型の変更は影響範囲が大きいのでおすすめはしません。）
なお、Name項目は必ず必須項目となります。入力任意項目として登録することはできません。


## Name項目のデータ型
データ型は、テキスト型か自動採番型を選択できます。
テキスト型を選択した場合は、常に値の入力が求められます。既存レコードと同じ値も登録できてしまうので、ユニークな値を登録した場合は別途重複ルール等を設定しましょう。
自動採番型を選択した場合は、自動的にユニークな値が登録されます。設定値のフォーマットも自由に設定することが可能です。

## Name項目はレコード名として検索結果で表示される
Name項目はSalesforce上の様々な箇所でレコード名として扱われます。例えば、関連リスト、ルックアップ検索時の表示名、グローバル検索やChatter検索の検索結果に表示されます。検索結果で表示される項目であることから、見る人がレコードを特定できるようなわかりやすい値を設定する必要があります。このことを踏まえると、データ型が自動採番だとわかりにくくなってしまう場合もあるかもしれません。Name項目を設定する時は、検索結果として表示される項目であることを意識してわかりやすい値となるようにしましょう。

## 【補足】セカンダリ項目
グローバル検索やChatter検索で検索結果として表示されるのはName項目のみですが、ルックアップ検索の検索結果にはName項目の他にもう1つの項目が表示されます。これをセカンダリ項目と呼びます。下の例では、電話番号が表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674790/494f32a4-4dd6-e023-6b01-36f7232c9deb.png)
このセカンダリ項目を活用し、検索結果をよりわかりやすくすることが可能です。
ただし、セカンダリ項目が表示されるのはルックアップ検索時のみなので、グローバル検索等では表示されません。そのため、Name項目にわかりやすい値を設定することは極めて重要です。
robloxでassistant その74

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

# 練習問題
AlignOrientationを、使え。

# 手順
- ServerScriptServiceに、scriptを追加。
- スクリプトを書く。

```

local part1 = Instance.new("Part", workspace)
part1.Position = Vector3.new(5, 0.5, -15)
part1.Anchored = false
local part2 = part1:Clone()
part2.Position = Vector3.new(-5, 0.5, -15)
part2.Parent = workspace
local alignOrient = Instance.new("AlignOrientation", part2)
alignOrient.Attachment0 = Instance.new("Attachment", part2)
alignOrient.Attachment1 = Instance.new("Attachment", part1)
while wait() do
	part1.CFrame *= CFrame.Angles(0, math.rad(5), 0)
end


```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/281b80a7-0cd4-9f35-f7cc-f7dee05abe8f.png)


以上。
robloxでassistant その73

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

# 練習問題
PathfindingServiceを、使え。

# 手順
- RiplicatedFirstに、localscriptを追加。
- スクリプトを書く。

```

local player = game.Players.LocalPlayer
print(player.Name)
local me = game.Workspace:WaitForChild(player.Name)
if me then
	print("me")
end
local NPC = game:GetService("ReplicatedStorage"):WaitForChild("npc"):Clone()
NPC.HumanoidRootPart.Position = Vector3.new(10, 0, -50)
NPC.Parent = game.Workspace
local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath()
path:ComputeAsync(NPC.HumanoidRootPart.Position, me.HumanoidRootPart.Position)
local waypoints = path:GetWaypoints()
for _, waypoint in pairs(waypoints) do
	NPC.Humanoid:MoveTo(waypoint.Position)
end

```

以上。
MacBook Air 2013をUbuntu23.10からUbuntu24.04にアップデート

# ubuntuのアップデートしたら(ちょっとだけ)ハマった話
とりあえず箇条書きにしておいて、あとでちゃんと書き直す日が来ることを期待したい。
MacBook Air 2013がなんだかわからない人のために、Intelベースの(だいたい)最終型のMacBook Airです。11インチの画面はコンパクトでとてもよいです。バッテリーはアップルで載せ替えてもらったので、まだ3,4時間ぐらいは持ちます。できることなら、もう一度新品のバッテリーに変えたいです。

---
- ssdのルートを暗号化していたので、アップデート後の再起動時にディスクの暗号化解除待ちメッセージが出たあとしばらくしてBusyboxに落ちる。
- 仕方ないのでgrub menuから23.10当時のkernel6.5を選んだらディスクの復号パスワード入力画面がでたので小躍りした。
- OS起動した。
- kernel6.8はこのハードウェアでは無理なのかな〜としばらく古いkernelのまま使う。
- なんとなくネットをさまよううちに、ディスクの復号化ができないのはそもそもkernelが内蔵ドライブを認識できてないためじゃないかな〜という漠然とした啓示をうける。
- Busyboxに落ちたとき、そういえば/dev/以下にssdらしきものがなかった。
- intel_iommuという仮想化支援機能に対応していないチップがのっているMBでは、ディスク関連へのアクセスができなくなるらしい。
- 新しいkernelは大抵の場合、intel_iommu=onで出荷されているそうだ。
- grub menuでeキーをおすと起動パラメータが編集できるので、編集してみた。
```
linux   /vmlinuz-6.8.0-31-generic root=/dev/mapper/vgubuntu-root ro quiet splash $vt_handoff
```
- この行の末尾に「intel_iommu=off」を追記した。
```
linux   /vmlinuz-6.8.0-31-generic root=/dev/mapper/vgubuntu-root ro quiet splash $vt_handoff intel_iommu=off
```
- 6.8カーネルでディスクの復号化パスワード入力画面が出た。
- パスワード入力後、無事起動したのでまた小躍りした。
- 毎回手入力するのは面倒なので、GRUBに書いてしまうことにする。
```
$ sudo vi /etc/default/grub
```
- GRUB_CMDLINE_LINUXに追記すれば、自動的に毎回適用されるらしい。
```
GRUB_CMDLINE_LINUX="intel_iommu=off"
```
- GRUBの設定を変更したら起動用ファイルも更新しないと反映されないのだった。
```
$ sudo update-grub2
```
- 完了

# おわりに
そういえば、USBドライブから起動した24.04のインストーラーからMBAのディスクが全く見えなかったのも、起動時にGRUBにiommuパラメータをオフにするように教えてあげれば解決するのかもしれないなあと思った。ちなみに`intel_iommu=pt`という設定もあるそうですが、MBAではoffの一択でした。
おしまい
【Flutter】flutter webの長いローディング時間に対応する

## この記事で紹介すること

Flutter Webでは初回のローディングがとても長いという致命的な問題があります。
実際に初回デプロイ後に確認した際に体感では、ブラウザ自体のローディング完了後に真っ白な画面が5秒以上表示されていた体感があります。

:::note info
本記事では、**その真っ白なローディング画面に対応するためにLottieを利用していい感じのローディングアニメーションを表示させる方法を紹介**します。
:::

## 作成物

下記のようにLottieのローディングが表示されます。
![flutter_loading.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261934/11c78004-9227-5de3-b5a3-505e41ee7da3.gif)

## 実装方法

### 1. `web/index.html`の<head>タグ内にLottie Playerのスクリプトと`.loading`用のスタイルを追加する

```html:web/index.html
<!-- これより上省略 -->
  <!-- Lottie animation -->
  <script src="https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js"></script>
  <script src="https://unpkg.com/@dotlottie/player-component@latest/dist/dotlottie-player.mjs" type="module"></script>

  <style>
    .loading {
      display: flex;
      justify-content: center;
      align-items: center;
      margin: 0;
      position: absolute;
      top: 50%;
      left: 50%;
      -ms-transform: translate(-50%, -50%);
      transform: translate(-50%, -50%);
    }
  </style>
</head>

```

### 2. `web/index.html`の`<body>`タグの最下部に`.loading`のdivタグとLottieアニメションを表示するコードを追加する

```html:web/index.html
<!-- これより上省略 -->
  <div class="loading">
    <dotlottie-player src="{ここにlottieのアニメーションのURL}" background="transparent" speed="1" style="width: 300px; height: 300px;" loop autoplay></dotlottie-player>
  </div>
</body>
```

### 3. ロード完了後に.loadingのdivを消す処理を追加

```dart:トップ画面のinitState function
import 'dart:html';

@override
void initState() {
  super.initState();
  
  // くるくるがあれば除去する
  final loading = querySelector('.loading') as DivElement?;
  if (loading != null) loading.remove();
}
```

## 参考記事

https://qiita.com/YuKiO-OO/items/02471f5087491f8507f9

https://techgamelife.net/2021/03/25/flutter-web-loading/
JSONAssertsを用いたJson比較、一部分だけ比較しないメモ

## JSONAssertsで遊ぶ

``` java
import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.CustomComparator;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.skyscreamer.jsonassert.comparator.Customization;

public class JsonComparisonTest {

    @Test
    void test_01() throws JSONException {
        // language=json
        String expect = "{ \"time\" : {\n" +
                "  \"insertTime\": \"201912010023\",\n" +
                "  \"updateTime\": \"202008111234\"\n" +
                "},\n" +
                "\"animal\": \"gorilla\"}\n";

        // language=json
        String actual = "{ \"time\" : {\n" +
                "  \"insertTime\": null,\n" +
                "  \"updateTime\": \"999999999999\"\n" +
                "},\n" +
                "\"animal\": \"gorilla\"}\n";

        JSONAssert.assertEquals(expect, actual,
                new CustomComparator(JSONCompareMode.STRICT,
                        new Customization("time.insertTime", (o1, o2) -> {
                            if (o2 == null) return true; // actualがnullの場合は無視
                            if (o1 instanceof String && o2 instanceof String) {
                                return ((String) o2).matches("201912010023"); // 正規表現で比較
                            }
                            return false;
                        }),
                        new Customization("time.updateTime", (o1, o2) -> {
                            if (o2 == null) return true; // actualがnullの場合は無視
                            if (o1 instanceof String && o2 instanceof String) {
                                return ((String) o2).matches(".*"); // 正規表現で比較
                            }
                            return false;
                        })
                )
        );
    }
}

```
Spring Batchのフォールトトレランスで無限ループが発生する話

### 結論
以下のページの一番最後に記載がある通り、「ItemProcessorはべき等になるように実装する必要がある」という話です。

https://spring.pleiades.io/spring-batch/reference/processor.html

### 起きたこと
Spring Batchで次のような実装をしたところ、無限ループが発生しました。

※事象を再現するための簡略化した処理です
```DemoBatchProcessor.java
@Component
public class DemoBatchProcessor implements ItemProcessor<MstUser, MstUser> {

	@Override
	public MstUser process(MstUser item) throws Exception {
		LocalDateTime now = LocalDateTime.now();
		item.setExpireDate(now);
		return item;
	}

}
```
```DemoBatchWriter.java
@Component
public class DemoBatchWriter implements ItemWriter<MstUser> {

	@Override
	public void write(Chunk<? extends MstUser> chunk) throws Exception {
		chunk.forEach(item ->{
			System.out.println(item);
		});
		throw new Exception(); // 例外を発生させる
	}

}
```

```DemoBatchConfig.java
@Bean("demoBatchChunkStep")
	Step demoBatchChunkStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
		return new StepBuilder("demoBatchChunkStep", jobRepository).<MstUser, MstUser> chunk(1, transactionManager)
				.reader(demoBatchReader).processor(demoBatchProcessor).writer(demoBatchWriter)
				.faultTolerant() //フォールトトレランスを設定
				.build();
	}
 ```


 ### なぜ起きるのか 
>チャンクがロールバックされると、読み取り中にキャッシュされたアイテムが再処理される場合があります。ステップが耐障害性を持つように構成されている場合 (通常、スキップまたは再試行処理を使用することによって)、使用される ItemProcessor はべき等になるように実装する必要があります。通常、これは、ItemProcessor の入力項目に対して変更を実行せず、結果であるインスタンスのみを更新することで構成されます。

上記の処理ではWriterの処理で例外を投げているため、チャンクがロールバックされます。
ドキュメントによると、その場合にキャッシュされたアイテムが再処理されることがあるようです。
実際、デバッグをおいてみると、ItemProcessorが再度呼び出されることがわかります。

今回の処理では、ItemProcessorの中で、Itemに対してLocalDateTime.now()をセットしています。
つまり、再処理されたときは、初回の処理とはItemの中身が変わっています。

```
MstUser(userId=1, userName=田中太郎, age=21, expireDate=2024-05-25T01:25:01.426943700)
MstUser(userId=1, userName=田中太郎, age=21, expireDate=2024-05-25T01:25:01.437740600)
MstUser(userId=1, userName=田中太郎, age=21, expireDate=2024-05-25T01:25:01.441745100)
MstUser(userId=1, userName=田中太郎, age=21, expireDate=2024-05-25T01:25:01.444741200)
・・・
```

すると、同じItemのリトライは何回まで、といった設定をしていたとしても、そもそも同じItemとしてみなされず、無限ループが発生してしまうようです。
※同じItemとしてみなされずに無限ループが発生する、の根拠となる部分は、ドキュメント内に明確な記載を見つけられませんでした。


### どうすればいいか
ドキュメントにある通り、ItemProcessorの中では、Itemに対して直接変更をかけるのではなく、新しいインスタンスを作成してWriterに渡す必要があります。

```DemoBatchProcessor.java
@Component
public class DemoBatchProcessor implements ItemProcessor<MstUser, MstUser> {

	@Override
	public MstUser process(MstUser item) throws Exception {
        // 新しいインスタンスを作成
		MstUser  mstUser = new MstUser();
		mstUser.setUserId(item.getUserId());
	    ︙
		LocalDateTime now = LocalDateTime.now();
		mstUser.setExpireDate(now);
		return mstUser;
	}

}
```

これで、無限ループが発生せずに、リトライやエラーの処理を行うことができます。
事象発生からドキュメントの記載にたどり着くまでかなり時間がかかりました…。
pySerial ：シリアル通信で受信データの前半部分が欠落するのでやってみたこと

#### 不具合：シリアル通信で受信データの前半部分が欠落する。

例：
”abcdefghijklmn” + 終了文字　というデータを受信したいが
"klmn" + 終了文字　しか受信できない。

なお、送受信の基本処理はpySimpleGUIで作った画面のボタンを押すことで制御し、受信処理はスレッドで回している。

``` serial.py
import PySimpleGUI as sg
import serial
import time
import threading

Ser = None #シリアルポート

def open_port(s_port):
    ser = serial.Serial()
    ser.baudrate = 9600
    ser.timeout = 0       # 読み取りタイムアウトの時間 0:即座にタイムアウト
    ser.parity = serial.PARITY_NONE
    ser.bytesize = serial.EIGHTBITS
    ser.stopbits = serial.STOPBITS_ONE
    ser.xonxoff = False 
    ser.port = 'COM' + s_port

    # 開いてみる
    try:
        ser.open()
        return ser
    except:
        messagebox.showerror('エラー', 'エラー：ポートが開けませんでした。')
        return None


tm_wait_rx = 0 #受信待ちタイマー
#送信処理
def Tx(ser):
    global tm_wait_rx

    Tx_Data = 送りたい文字列データ
    if ser.isOpen() == True:
        ser.write(Tx_Data.encode('ascii')) 
        ser.flush() #送信するまで待機
        tm_wait_rx = 1000 #受信待ちタイマー1000ミリ秒


#受信処理
def Rx_Proc(ser):
    global tm_wait_rx
    global End_Mark          #'通信の終了文字
    if ser == None:
        return
    elif ser.isOpen() == True:
        line = ''
        while ser.isOpen() == True: 
            try:
                r = ser.read(1) #1バイトずつ読む　
                if r == b'':
                    return
                line += r.decode('ascii') 
                if r.decode('ascii')  == End_Mark:
                    このへんで受信データ line を処理
                    break

            except:
                messagebox.showerror('エラー', 'エラー：受信処理に異常')
                break
        tm_wait_rx = 0 #受信待ちタイマーをクリア

    else:
        return

#受信処理をスレッドでまわす
def Rx_Proc_th():
    global Ser
    global tm_wait_rx
    while True:
        Rx_Proc(Ser)
        time.sleep(0.001)
        if tm_wait_rx > 0:
            tm_wait_rx -= 1  #受信待ちタイマーを0.001秒ごとに減算


layout = ここで画面パーツを定義する

window = sg.Window('シリアル通信テスト', layout, return_keyboard_events=True, enable_close_attempted_event=False)

            
thread2 = threading.Thread(target=Rx_Proc_th, )
thread2.start()


#ループで送信ボタンが押されるのを待つ
while True:
    event, values = window.read(timeout=50) #画面イベントを待つ

    if tm_wait_rx > 0:  #受信待ち中は何もしない
        continue
    
    elif event == 'com_open':
        Ser = open_port(1)

    elif event == '送信':
        Tx(Ser) #データ送信
            
```

### 解決？方法

１．画面イベント待ちのタイムアウトを短くした。←これは関係ないっぽい

``` serial.py
#ループで送信ボタンが押されるのを待つ
while True:
    event, values = window.read(timeout=1) #画面イベントを待つ　タイムアウト1ms

```

２．念のためシリアルポートの受信タイムアウトを長くした。←多分これが正解

``` serial.py
def open_port(s_port):
    ser = serial.Serial()
    ser.baudrate = 9600
    ser.timeout = 0.1       # 読み取りタイムアウトの時間 100ms
    ser.parity = serial.PARITY_NONE
    ser.bytesize = serial.EIGHTBITS
    ser.stopbits = serial.STOPBITS_ONE
    ser.xonxoff = False 
    ser.port = 'COM' + s_port

```


受信タイムアウトが短すぎるのが原因のようです。
ただ、なぜ受信データの先頭部分だけが欠落するのか謎・・・
システムデータが肥大化した時の解消法

## キャッシュの削除
`sudo rm -r /Library/Caches`
`sudo rm -r ~/Library/Caches`
`sudo rm -r /System/Library/Caches`

## バージョン管理、開発環境などの整理
`conda clean --all`
`brew cleanup`

## 参考
[お使いのMac上でシステム容量を消去する5つの方法](https://macpaw.com/ja/how-to/clear-system-storage-mac)
AWSのWindowsインスタンスでAMIを作る時はSysprepを忘れずに

## 経緯
使用ライブラリの都合上、Windowsインスタンスを利用していました。環境構築が終わり、カスタムAMIを作ったところ、このAMIを使って起動したインスタンスにFleetManagerのキーペアを指定して接続できなくなりました。
結論から言うと、WindowsインスタンスからAMIを作るときにはSysprepを使用してからAMIを作る必要がありました。

## 環境と前提
- WindowsServer 2016 （環境古いです。。）
- SessionManagerの設定が済んでいること
- FleetManagerのキーペアで接続できるようにインスタンスにIAMとキーペアが指定されていること

## 手順
### AMIを作る前にsysprepでインスタンスを停止する
AMIを作りたいインスタンスに接続し、 EC2 Launch Settings を開きます。
![EC2 Launch Settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123946/b9085b53-a1c1-4642-5eba-765de4d4aa0d.png)

Administrator の Password を後で復号化するために Random を指定し、Sysprepを使ってシャットダウンします。

### AMIを作成する
停止したインスタンスを指定してAMIを作ります
![Create_AMI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123946/afce06e1-6185-51bb-45a9-52c7fa51bbf2.png)

### パスワードを復号化する
AMIからインスタンスを作った後、Windowsのパスワードを取得を行います。
![Get Windows Password.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123946/e7463f7a-8e0d-80c8-d3eb-6c67eac41df9.png)

元のインスタンスで利用していたFleetManagerのキーペアを指定してパスワードを復号化します。
![Encrypt_Password.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123946/61efd240-e5a4-4ec3-6d54-058c9a33b77a.png)

## 参考

https://repost.aws/ja/knowledge-center/ec2-windows-password-not-available-error

https://repost.aws/ja/knowledge-center/sysprep-create-install-ec2-windows-amis
Raspberry Piにk8s+Calicoを導入するときはlinux-modules-extra-raspiを入れろ

一生k8sでトラブルマン
うっかりRaspberryPiを吹き飛ばしてしまい、止む無く再構築を迫られたk8s。
せっかくならCalicoで構築しようと思いいたったのがトラブルの始まりでした。

Calicoに関するPodがContainerCreatingのまま立ち上がりません。
いつも通り、describeするとエラーログがちらほら
```
> kubectl describe pods -n calico-system <立ち上がっていないpod>

~~~ failed to create host netlink handle: protocol not supported
```

解決方法は表題の通り

```bash
apt install linux-modules-extra-raspi
```
参考：https://github.com/canonical/microk8s/issues/2680

立ち上げの度にトラブルので、kubernetes立ち上げる時はちゃんとドキュメント読もうね（N回目）
webpack.config.jsの設定エラーについて



# はじめに
現在、大学の研究室サイトを作成しています。（初めてのWeb開発中）
そこで、今回は、作成中に困ったことを、備忘録として記事にします。
具体的な内容として、HTMLでimg要素に指定した画像がローカルサーバーで表示されなかったことについて、解決までの流れを説明します。

## エラーが発生した状況
1 . フォルダ構成
フォルダ構成は以下のようになっています。
 ```
university-lab-site/
├─ .vscode
├─ dist
├─ node_modules
├─ src/
│  ├─ assets
│  │  ├─ fonts
│  │  └─ images/
│  │     └─ img1.jpg
│  ├─ scripts/
│  │  └─ main.js
│  ├─ styles/
│  │  └─ main.css
│  ├─ index.js
│  └─ index.html
├─ .gitignore
├─ package-lock.json
├─ package.json
└─ webpack.config.js
```

2\. HTMLの編集
HTMLのimg要素のsrc属性値に相対パスで表示したい画像ファイルを指定。
```index.html
<!DOCTYPE html>
<html lang="ja">
 <head>
     <meta charset="UTF-8">
     <-- 以下省略 -->
 </head>
<body>
    <main>
        <div class="main-visual">
            <img src="assets/images/img1.jpg" alt="メイン画像">
        </div>
    </main>
</body>
</html>
```
3\. webpack-dev-serverを用いて確認
npm startコマンドでローカルサーバーを立ち上げます。

**【結果】**
画像は表示されず、alt属性値に設定したテキストのみ表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336555/eff68076-c00a-8499-6926-3f04fb8fff76.png)

## エラーが発生した原因
### webpack-dev-serverによって提供されるファイルのディレクトリの指定が間違っている


* 画像が表示されない時の設定
``` webpack.config.js
devServer: {
    static: {
        directory: path.join(__dirname, 'dist')
    },
    compress: true,
    port: 9000,
    open: true,
}
```
※devServerオブジェクト内の、staticオブジェクトにある、directoryプロパティのjoinメソッドの引数に**dist**が指定されている。しかし、**dist**フォルダの役割はビルドプロセスによって生成される出力ディレクトリである。
## エラーの解決方法
### webpack-dev-serverによって提供されるファイルのディレクトリの指定を変更する
* 画像が表示された時の設定
``` webpack.config.js
devServer: {
    static: {
        directory: path.join(__dirname, 'src')
    },
    compress: true,
    port: 9000,
    open: true,
}
```
※devServerオブジェクト内の、staticオブジェクトにある、directoryプロパティのjoinメソッドの引数に**src**を指定する。ここで、**src**ディレクトリは、HTML、JavaScript、CSS、画像などが格納されている。

:::note info
ポイント
devServer.static.directoryは、webpack-dev-serverが静的ファイルを提供するためのルートディレクトリ。
distフォルダを指定すると、ビルド後のファイルがない限り、画像や静的ファイルは提供されない。
srcフォルダを指定すると、ソースファイルを直接提供するため、画像が表示される。
:::

## まとめ
今回は、localhost上（ローカルサーバーを立ち上げた時）に画像が表示されない問題について、研究室サイトを作成している最中に発生したため、解決までの流れを説明させていただきました。
初めて技術記事を書いたのですが、Markdown形式に少し戸惑い気味でレイアウトに改善する余地が多少あったり、自分なりに理解しやすい構成を考えて、表現する難しさを体感することができました。さらに、技術記事を書けるように、日々取り組んでいきたいです。
Webアプリ開発の手順と必要な言語・フレームワークを解説

この記事では、Webアプリ開発の基本的な手順から必要なプログラミング言語やフレームワークまでを解説します。また、Webアプリとスマホアプリの違いや開発事例、勉強法についても紹介します。

<h2>Webアプリとは？スマホアプリとの違い

Webアプリとスマホアプリの違いについて解説します。それぞれの特徴や利点、デメリットについて比較します。

<h2>Webアプリを作るための主な5つの手順

Webアプリを開発する際の主要な手順について紹介します。要件定義からデプロイまでの流れを具体的に説明します。

<h2> Webアプリ開発に必要なプログラミング言語

Webアプリを開発するために必要なプログラミング言語について紹介します。主要な言語やフレームワークについて解説します。

<h2> Webアプリの開発事例

実際のWebアプリ開発事例を紹介します。有名な企業やサービスの事例を通じて、Webアプリの可能性を理解します。

<h2> Webアプリ開発におすすめの勉強法3選

Webアプリ開発を学ぶための効果的な勉強法を紹介します。オンラインコースや書籍、プロジェクト参加などの方法を提案します。

Webアプリ開発における基本的な手順や必要な言語・フレームワークについてまとめます。また、学習のポイントや今後の展望についても述べます。

この記事を通じて、Webアプリ開発に興味を持つ方が基礎から実践までを理解し、効果的に学ぶ手助けとなるでしょう。

「Webアプリ開発の手順と必要な言語・フレームワーク」を解説した記事にご興味のある方は、以下のリンクをご覧ください。
https://hblab.co.jp/blog/web-application_development-procedure/
選択バイアス

私たちは今や様々なライブラリあるいはプログラミング言語によって簡単にデータ分析ができるようになりましたが、データ分析をやる前に疑うべきこともあります。
一つが目的変数に対して説明変数が妥当かどうかが一点目。

https://qiita.com/murasaki1994/items/31b9818cb714b504625d

そしてもう一点目が特に人文統計などアンケート調査で考えられるものとしてバイアスです。
バイアスは多くありますが、代表的なバイアスとしては
- 選択バイアス
- 情報バイアス

というのがあります。

# 選択バイアス
このバイアスはサンプルから偏った手法で観察対象集団を抽出する事で発生します。
基本的に抽出は無作為にするものですが、例えばサンプルの中でファッションへの関心の有無について抽出して調査する時にファッション雑誌を買っている人だけを抽出した場合は当然ですがファッション雑誌を買うくらいなら関心がある人の方が多いと考えられます。
## 制御方法
先述した通りに偏った手法で観察対象集団からサンプルを抽出することで発生してしまうので無作為に抽出する事、および何らかの手法で対象集団に働きかけてできるだけ高い参加率を目指すことです。その中で参加者の負担をできるだけ少なくして報酬など含め調査に協力する事のメリットを出すようにすることで高い参加率を目指す必要があります。

# まとめ
そう考えるとかぐや様のアニメでやっていたサンプルセレクションバイアスという言葉はこれかもしれませんね。

# 参考文献
基礎から学ぶ 楽しい疫学　第4版
Bash sed コマンド使い方

# Bash Sed コマンド使い方


```bash
sed -r -i.bk -e 'スクリプト' 入力ファイル
```

# sed オプション

| オプション | コマンド内容 | 
| --- | --- |
| -e | スクリプトの前に配置するオプション | 
| -E | 拡張正規表現を使用する(-rと同じ) | 
| -r | 拡張正規表現を使用する(-Eと同じ) | 
| -f | 指定したファイルに記載されているsedスクリプトを実行する。 | 
| -n | 標準出力へ出力しない。(pスクリプトと併用を前提) | 
| -i | 入力ファイルを直接編集する。 | 
| -i.拡張子 | バックアップファイルを作成した後に直接編集する。 | 

# スクリプトアドレス (スクリプト前半)

| 入力値 | 内容 | 
| --- | --- |
| 指定なし | ファイル全体を対象とする。 | 
| 数字 | 行番号を指定する。行頭行は、1 | 
| /正規表現/ | 正規表現にマッチした行を処理対象とする。 | 
| $ | 最終行を指定する。 | 
| アドレス,アドレス | 範囲指定。 | 
| アドレス,+行数 | 開始行と行数分を処理対象とする。 | 


# スクリプト内容 (スクリプト後半)

| 英字 | 形式 | 内容 | 
| --- | --- | --- |
| i | i 文字列 |指定したアドレスの行に新しい行(引数の文字列)を追加する。<br>指定した文字列が指定した行に収まるように文字列(行)を追加する。| 
| a | a 文字列 |指定したアドレスの次行に新しい行(引数の文字列)を追加する。<br>指定した文字列が指定した行に収まるように文字列(行)を追加する。| 
| c | c 文字列 | 指定したアドレスの行の内容を引数の文字列に変更する。 | 
| d | d | 指定したアドレスの行を削除する。 | 
| s | s/置換前/置換後/g | 置換前の文字列を置換後の文字列へ置換する。 | 
| r | r ファイルパス | 指定したファイルの文字列を、挿入する。 | 
| p | p |指定したアドレスの行内容を表示する。<br>基本的には-nオプションと併用する。| 
| = | = |指定したアドレスの行番号を表示する。<br>基本的には-nオプションと併用する。|
【Next.js】Imageコンポーネントの画像最適化を無効化する方法

## 個別に無効化する

特定のImageコンポーネントのみ画像最適化を無効化するには`unoptimized`propsを`true`にします。

```jsx
import Image from 'next/image'
 
const UnoptimizedImage = (props) => {
  return <Image {...props} unoptimized />
}

```

## 全て無効化する

全てのImageコンポーネントで画像最適化を無効にするには`next.config.js`に以下のように記述します。

```js:next.config.js
module.exports = {
  images: {
    unoptimized: true,
  },
}

```

https://nextjs.org/docs/app/api-reference/components/image#unoptimized
【AZ-900】氷河期世代のAZ-900合格記

# 自己紹介
　４０代半ばのおじさんソフトエンジニアです。初投稿なので少し自己紹介をさせてください。

　新卒後、東京のとあるブラックなメーカで勤務。組込系開発、アプリケーション開発に従事し、最終的にはソフト開発リーダー(チームメンバー10名)。

  業務では、要件定義、設計、実装、評価、顧客対応を経験し、デジタル土方として多種多様な経験を積む。海外案件の機会に恵まれ、英語を勉強しTOEIC950を取得。ブラック企業では、(ちゃんと支払いされる)残業、サービス残業、休日出勤が続き、家庭崩壊の危機に。
  
  　仕事では人間関係は良好で意外と仕事を楽しんでいたが、さすがに家族を犠牲にしてまで働くのはおかしいと気づき、転職を決意。新天地では、クラウド関連の知識が必要になり、アウトプットの場を設けるためにQiitaデビューを思いたつ。会社では主にAzureを使用する環境のため、まずはAZ-900を取得した。

# AZ-900の勉強法
AZ-900取得で利用した教材と問題集について紹介する。

## 教材
* [Udemy: 合格への近道！Azure Fundamentals AZ-900 試験対策講座 (Makoto Okada) ](https://www.udemy.com/share/107gBM3@mujBvZ-rdeYeMO0OsHTQ19n4ATykcG6ttSU1bBpYpmTto0f1paG0WyxJs10p8nw6Ag==/)
→ はじめの一歩として使用する教材としては良いかも。但し、難易度が易しめなので、本教材だけで学習してもAZ-900の取得は難しいと思われる。他の教材による学習や問題集でも練習すること。

* [(模擬問題付き)徹底攻略 Microsoft Azure Fundamentals教科書[AZ-900]対応](https://amzn.asia/d/5fARh8y)
→ 内容は多少古いが、上記のUdemyの教材よりは詳細に説明されている。私はUdemyで学習した項目について、本テキストで学習し、必要な知識の理解を深めました。

## 問題集
* [Udemy: 最短で合格！Azure Fundamentals AZ-900 試験対策問題集 (Makoto Okada)](https://www.udemy.com/share/106ezY3@4NDIFqvYmZodTfeD6o0RVovSoyNZYGfPCUd0AfAQFFbsnYKvNSqrv6bbsnICGSI5MQ==/)
→ 実際の試験と比較し難易度が低い。90%以上の正解率を目指すぐらいで頑張りましょう。2024年5月時点で受験したAZ-900に追いついていない部分は多少あり。

* [Microsoft プラクティス](https://learn.microsoft.com/ja-jp/credentials/certifications/azure-fundamentals/?practice-assessment-type=certification)
→ AZ-900試験申し込みサイトに記載されている、Microsoftが用意している試験。学習スコープについて一通り学習を終えた後に本試験問題を実施した方が良いと思う。分からない問題があれば、キーワードをメモし、再学習しましょう。

* ★重要★Azure Portal
教材で学びながら項目について、AzurePortal上で実際に操作し理解を深めた。問題集ばかり解いても、実業務はできないので、必ず手を動かして理解をするようにした。

## 受験に向けた工夫
* 受験日の宣言
会社のお同僚にAZ-900を受験することを宣言した上で試験も予約。自分自身を追い詰める環境を作り退路を断った。

* 計画
教材の項目をエクセルシートに学習ペースを計画。進行具合を見える化して、自身のモチベーションにつなげた。

* 邪念の排除
生活の見直して勉強時間を妨げるものを物理的に断った。私の場合は、X(Twitter)で不必要な時間を費やしていたので、スマホからアプリを削除した。
 
* スキマ時間の活用
通勤中のバスや電車でUdemyを活用して学習。眠くならないように、席には座らずに敢えて立ちながら

* 実践環境の用意
Azureアカウントを作成し、教材で学びながら内容について、実際に操作し理解を深めた。

# これからの目標
2024年の目標をここに宣言する。
- DP900（目標　2024年６月末）
- AZ104（目標　2024年８月末)
- AZ204（目標　2024年11月末）

# 終わりに
こんなおじさんでも頑張れることを証明したい。４０代のおじさんエンジニア同志よ、お互い頑張りましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799551/b2f51f0a-55a5-ed0d-444c-b8eac506c08f.png)
https://th.bing.com/th/id/OIG3.B7EiJGiSmK5wNC5ery7j?pid=ImgGn
Vue3 CompositionAPIでdraggableを用いた親子の並び替え処理の実装

# 記事を書こうと思ったキッカケ
業務の中で、Vueで並び替えた要素をバックエンド側にソート順も含めて送信し保存する実装を行ったのですが、なかなかに苦戦してしまったので備忘録をと思いまして・・・

# 動作イメージ
>親の中に子要素があり、子要素の順番は子要素間で入れ替えが行えて親要素は親要素間で入れ替えができるような動きを作りたかった(語彙力)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1149363/4ffa2764-b2ec-10ac-41cd-8bdf2fb49231.png)

# 使用したライブラリ
### VueDraggable
[https://github.com/SortableJS/Vue.Draggable](https://github.com/SortableJS/Vue.Draggable)


# 実装したコードの一例

```vuejs:Draggable.vue
<script setup>
const props = defineProps({
  draggable: {
    type: Object
  },
})

// 親要素を追加する関数
const addParent = () => {
  const newSort = form.draggable.length ? Math.max(...form.draggable.map(el => el.id)) + 1 : 1;
  const newId = form.draggable.length ? Math.max(...form.draggable.map(el => el.id)) + 1 : 1;

  form.draggable.push({
    id: newId,
    sort: newSort,
    title: '',
    items: []
  });
};

// 子要素を追加する関数
const addChild = (parentId) => {
  const parent = form.draggable.find(p => p.id === parentId);
  if (parent) {
    const newId = parent.items.length ? Math.max(...parent.items.map(el => el.id)) + 1 : 1;
    const newSort = parent.items.length ? Math.max(...parent.items.map(el => el.sort)) + 1 : 1;
    parent.items.push({
      id: newId,
      sort: newSort,
      title: '',
    });
  }
};

// 親要素を削除する関数
const deleteParent = (parentId) => {
...
};

// 子要素を削除する関数
const deleteChild = (parentId, childId) => {
...
};


// 親の順番を入れ替えたときに情報を更新する関数
const atEndParent = () => {
...
};
// 子の順番を入れ替えたときに情報を更新する関数
const atEndChild = (parentId) => {
...
};
// 保存
const submit = () => {
...
}
</script>

<template>
  <draggable v-model="form.menu" group="parents" item-key="id" @end="atEndParent">
    <template #item="{ element: parent }">
        <div class="parent">
        ...親要素の削除ボタンとか子要素追加ボタンとか入れる
        </div>
    <draggable v-model="parent.items" group="children" item-key="id" @end="atEndChild(parent.id)">
     <template #item="{ element }">
            <div class="childlen">
                 ...子要素に詰め込みたいものを入れる
            </div>
        </template >
     </draggable>
    </template >
  </draggable>
</template>

```
:::note warn
引っかかったポイント①
 単純に動かなかった。
:::

vue3からは#item="{ element } 
 ↑この記載が必須になり、記載がないとエラーになります。
 完全にvue2の情報を見ており、初歩的なミス過ぎて書くかどうかも迷いました()
 
:::note warn
引っかかったポイント②
要素を入れ替えて表示上は入れ替わっているが、sortの値が変動しない
:::

ソート順を保存するためにsortの値を保持させるために[@end](https://github.com/SortableJS/Vue.Draggable?tab=readme-ov-file#events)イベントで並び替えが終わったときに並び順を更新する処理を入れていなかったためでした・・・

※ @endはドラッグアンドドロップが終わった際に着火するイベントになります。
他にもvuedraggableにはstart, add, removeなど便利なイベントトリガーがあるので気になる方は調べてみてください

:::note warn
引っかかったポイント③
親要素は親要素同士、子要素は子要素同士で入れ替えをしたかったのにうまくいかない。
:::
今回、親は親同士、子は子同士でのみ入れ替えをしたかったのですが、どうやらgroupで指定していないといけなかったようでgroupを指定してあげるとgroupで指定した値が合致したコンポーネント間でしか移動ができないように制限ができます。
→　group="parent"とgroup="children"はこれで行き来できないですね
# さいごに
自分自身がサーバーサイドをメインに実装しておりフロントをあまり触らないこともあり(言い訳)
こんな便利なライブラリを用意してくれている世の有識者に対して足を向けて眠れないような恥ずかしい箇所で躓いてしまいましたが、個人的にはいい勉強になったかなと思います。
フロントエンドの領域も奥が深く、サーバーサイドにはない面白さを感じられたので、今後も積極的に学習を進めていこうと思いました。