OmniAICreator/Qiita-1.07M huggingface dataset:
【Mac】dateコマンドで過去の日時を出力する方法

`date`コマンドを使用して1日前の日時を出力するには以下のように実行します。

```terminal
date -v-1d
```

```terminal
% date   
2024年 9月 5日 木曜日 23時57分12秒 JST

% date -v-1d
2024年 9月 4日 水曜日 23時57分21秒 JST

```
【初心者の備忘録】Gitリポジトリの初期化とリモートリポジトリへのプッシュ

Gitリポジトリの初期化からリモートリポジトリへのプッシュまでの手順をまとめました。
備忘録として役立ててください。

**1. Gitリポジトリの初期化**
プロジェクトのディレクトリに.gitフォルダが作成され、Gitでバージョン管理ができるようになります。

```
git init
```

メッセージ:

```
Initialized empty Git repository in /path/to/your/project/.git/
```

**2. ファイルの作成と追加**
次に、README.mdファイルを作成し、それをGitのステージングエリアに追加しました。

```
echo "# My Project" > README.md
git add README.md
```

**3. 最初のコミット**
ステージングエリアに追加したファイルをコミットしました。これにより、変更がリポジトリに保存されます。

メッセージ:
```
git commit -m "Initial commit"
```

```メッセージ:
[master (root-commit) 960c36b] Initial commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
```
**4. リモートリポジトリの設定**
GitHub上にリポジトリを作成し、そのリモートリポジトリのURLをローカルリポジトリに設定しました。

```
git remote add origin https://github.com/your-username/your-repository.git
```

**5. リモートリポジトリへのプッシュ**
ローカルリポジトリの変更をリモートリポジトリにプッシュしました。これにより、GitHub上のリポジトリに変更が反映されます。

```
git push -u origin master
```

メッセージ:

```
info: please complete authentication in your browser...
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 231 bytes | 77.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote:      https://github.com/your-username/your-repository/pull/new/master
remote:
To https://github.com/your-username/your-repository.git
 * [new branch]      master -> master
branch 'master' set up to track 'origin/master'.
```

**6. アカウント変更時の対応**
GitHubのアカウントを変更する場合、リモートリポジトリのURLを新しいアカウントのリポジトリに変更します。

```
git remote set-url origin https://github.com/new-username/new-repository.git
git push -u origin master
```

これで、リモートリポジトリに変更が反映されます。
chrome-remote-interfaceでChromeを外部からJSで操作するサンプル

JavaScriptでChromeを外部から操作して、任意のJavaScriptを実行することができるか調べたところ
[chrome-remote-interface](https://github.com/cyrus-and/chrome-remote-interface)を使うと簡単にできることが分かりました

https://github.com/cyrus-and/chrome-remote-interface

[Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)というリモートデバッグ用プロトコル経由でChromeを操作する(DevToolsの機能を外部から操作することができる)ようです

([PlayWright](https://playwright.dev/)のようなE2Eテストツールでもできるのですが、純粋にChromeを操作するツールを探してみました)

## chrome-remote-interfaceを使うための準備

npmで`chrome-remote-interface`をインストールします
```
$ npm i chrome-remote-interface
```

ES Modulesを利用可能にするため`package.json`に下記の設定を追加します

```
  "type": "module",
```

リモートデバッグを有効にしてChromeを起動しておきます
（Chromeが起動している場合は、先に終了してから下記コマンドを実行します）

```
chrome --remote-debugging-port=9222
```
※Chromeのインストールパスは適宜補ってください

## 指定したURLを開いて、画面のDOMを変更するサンプルスクリプト

スクリプトを起動する前に、Chromeをデバッグモードで起動しておきます

スクリプトを実行すると`example.com`が表示され、&lt;h1&gt;タグが赤色になります
```
$ node cdp-open-url.js
```

![alt text](https://github.com/murasuke/chrome-devtools-protocol/raw/master/image.png)


```JavaScript:cdp-open-url.js
import CDP from 'chrome-remote-interface';

async function openURL() {
  let client;
  try {
    // Chromeに接続
    client = await CDP();

    // 必要な機能を有効化
    const { Page, Runtime } = client;
    await Page.enable();
    await Runtime.enable();

    // 指定したURLを開く
    const url = 'https://example.com';
    await Page.navigate({ url });
    await Page.loadEventFired(); // 読み込み完了を待つ

    // <h1>を赤くする
    const expression = `document.querySelector('h1').style.color = 'red'`;
    await Runtime.evaluate({ expression });
  } catch (err) {
    console.error(err);
  } finally {
    if (client) {
      await client.close();
    }
  }
}

openURL();
```


## Chrome上でGemini nanoを実行して、結果を受け取ってみる

[Chrome128(stable)で利用可能になったGemini Nanoを試してみる](https://qiita.com/murasuke/items/5ad4f7d338fe2054211e)という記事でChromeに導入した`Gemini nano`をブラウザ外部から利用してみます

Gemini nanoのインストール等、準備はこちら(https://qiita.com/murasuke/items/5ad4f7d338fe2054211e)

Geminiの呼び出しは非同期関数なので、呼び出し時に完了を待つために`awaitPromise: true`をつける必要がありました

```javascript
    const result = await Runtime.evaluate({
      expression, // Gemini呼び出しjs
      awaitPromise: true, // 非同期処理を待つ
    });
```

実行結果（Chrome外部からGemini nanoを呼び出して、結果を受け取ることができました）
```bash
$ node cdp-gemini.js
result:  日本で一番高い山は標高3,776メートルの富士山です。
```

```JavaScript:cdp-gemini.js
import CDP from 'chrome-remote-interface';
async function callGemini() {
  let client;
  try {
    // Chromeに接続
    client = await CDP();

    // 必要な機能を有効化
    const { Page, Runtime } = client;
    await Page.enable();
    await Runtime.enable();

    // gemini nanoを呼び出して結果を待つ
    const expression = `
      (async function() {
        const session = await window.ai.createTextSession();
        const message = await session.prompt("日本で一番高い山はなんですか？");
        return message;
      })();
    `;

    const result = await Runtime.evaluate({
      expression,
      awaitPromise: true, // 非同期処理を待つ
    });

    // 実行結果を表示
    console.log('result:', result.result.value);
  } catch (err) {
    console.error(err);
  } finally {
    if (client) {
      await client.close();
    }
  }
}

callGemini();

```
Auth0でClientCredentialsFlowを試す

## 0.初めに

OAuth2.0ではauthorization code flowが有名ですが、認証するユーザが存在しない場合はClientID, ClientSecretを使ってアクセストークンを発行する[Client Credentials Flow](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)という仕様も存在します。

今回はAuth0を使ってClient Credentials Flowによるアクセストークンの取得までをまとめます。

## 1.クライアントの作成
Auth0にログインし、ダッシュボードのApplicationsから「+Create Application」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/6d8e8375-c839-f04a-9ea6-e6c4d9c79fbf.png)

任意のNameを入力し、「Machine to Machine Applications」を選択し、「Create」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/ff2a1ade-66f1-6f33-2989-7052f5b98e07.png)


permissionsでclient_credentialsのcrudを選択し、「Auuthorize」をクリックします。
※ここはどこまで必要なのか未確認です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/999fb4b3-a268-d949-ce8d-d0a0357c32b5.png)

ここまででクライアントが作成されます。
赤線の部分にはClientIDが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/c4408cca-c92a-e736-bdbf-c13956858668.png)

Secretは「Credentials」から確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/edf792a9-4e6e-1c89-99d2-24071ad41866.png)


## 2.ClientCredentialsFlowによるアクセストークンの取得

全ては「Quickstart」に記載されています。
「Getting an access token for your API」に各言語でのアクセストークンの取得方法が記載されています。

今回は手っ取り早くCurlで試してみます。Curlに記載のコマンドをターミナルに貼り付けて実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/f4bab131-dc21-cdd3-a11f-5111a002995a.png)

取得できていそうです🎉
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/9bd71a2f-c611-3ec4-c8cb-f0b9b31dd214.png)


トークンのペイロードはこんな感じになってました。
ここは使用するサービスによってカスタマイズの余地がありそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2527942/b8f1006d-8ed6-6ce1-82c5-d83f62665c71.png)

## 3.終わりに
auth0でClientCredentialsFlowを試してみましたが、30分もかからず検証ができました。
今後他のフローやIDaaS製品について触る機会があれば検証してみます。
たくさんの非同期処理をTask.Run()させたいけど同時に動かない

# 参考にさせて頂いた記事
https://oita.oika.me/2016/02/18/task-and-threadpool/

# 言い訳
実際には業務中に問題が出てきてサンプルソースは都合よく作ったものなので悪しからず

# .NETのばーじょん
.NET 8.0

# とりあえずやってみる
```
// めちゃくちゃHello, Worldさせたい
List<Task> helloWorldTaskList = new List<Task>();

// とりあえず100個のTaskを生成してみる
for (int i = 0; i < 100; i++)
{
    int taskNo = i;

    helloWorldTaskList.Add(Task.Run(() =>
    {
        for (int j = 0; j < 10000000; j++)
        {
            Console.WriteLine($"Task{taskNo}：Hello, World!");
        }
    }));
}

// すべてのタスクの終了待ち
await Task.WhenAll(helloWorldTaskList);

Console.WriteLine("終了");
```

[int taskNoを使用する理由](https://qiita.com/Tokeiya/items/373639164db38e309773)はさておき、実行しているタスクが偏っている気がするので、初回起動のログを仕込んで確認してみる。

```
List<Task> taskList = new List<Task>();
Stopwatch sw = Stopwatch.StartNew();

// 15個のTaskを生成してみる
for (int i = 0; i < 15; i++)
{
    int taskNo = i;

    taskList.Add(Task.Run(() =>
    {
        Console.WriteLine($"{sw.ElapsedMilliseconds}ms後 Task{taskNo}：★起動");
        Thread.Sleep(5000);
    }));
}

Console.WriteLine($"{sw.ElapsedMilliseconds}ms後 Task生成終了");

await Task.WhenAll(taskList);

Console.WriteLine("終了");
```
実行してみる。
```
26ms後 Task2：★起動
35ms後 Task生成終了
26ms後 Task0：★起動
26ms後 Task1：★起動
26ms後 Task3：★起動
26ms後 Task4：★起動
27ms後 Task5：★起動
27ms後 Task6：★起動
38ms後 Task7：★起動
823ms後 Task8：★起動
1338ms後 Task9：★起動
1855ms後 Task10：★起動
2859ms後 Task11：★起動
3873ms後 Task12：★起動
4381ms後 Task13：★起動
5052ms後 Task14：★起動
終了
```

8つ目までは早く実行されているけど、15個目についてはかなり後に実行されている。

# ThreadPoolについて

へんしゅうちゅう

# ThreadPool.SetMinThreads()を使用してみる
```
// ↓ ここを追加 ↓
int workerThread;
int completionPortThread;
ThreadPool.GetMinThreads(out workerThread, out completionPortThread);
Console.WriteLine($"WorkerThread：{workerThread} -> 15");
ThreadPool.SetMinThreads(15, completionPortThread);
// ↑ ここを追加↑

List<Task> taskList = new List<Task>();
Stopwatch sw = Stopwatch.StartNew();

for (int i = 0; i < 15; i++)
{
    int taskNo = i;

    taskList.Add(Task.Run(() =>
    {
        Console.WriteLine($"{sw.ElapsedMilliseconds}ms後 Task{taskNo}：★起動");
        Thread.Sleep(5000);
    }));
}

DateTime curTime = DateTime.Now;
Console.WriteLine($"{sw.ElapsedMilliseconds}ms後 Task生成終了");

await Task.WhenAll(taskList);

Console.WriteLine("終了");
```

# 検証結果
```
WorkerThread：8 -> 15
9ms後 Task2：★起動
9ms後 Task0：★起動
9ms後 Task1：★起動
10ms後 Task3：★起動
14ms後 Task4：★起動
19ms後 Task5：★起動
24ms後 Task6：★起動
30ms後 Task7：★起動
34ms後 Task9：★起動
34ms後 Task8：★起動
39ms後 Task10：★起動
43ms後 Task生成終了
43ms後 Task11：★起動
48ms後 Task12：★起動
53ms後 Task13：★起動
57ms後 Task14：★起動
終了
```

先ほどと比べて最後のタスクの起動速度が大幅に速くなった。

# 後記
へんしゅうちゅう
Railsでwebpack-dev-serverが起動できないエラー

## はじめに
デイトラWeb開発コースを進めている中でwebpack-dev-serverが実行できず、めちゃくちゃ解決に時間をかけてしまったため、原因と解決策を残しておきます。
時間はたくさん使ってしまいましたが、一方で理解が深まった面もあるので、その点も最後にアウトプットします。


## 問題
Railsのプロジェクトで`bin/webpack-dev-server`を実行すると、`Command "webpack-dev-server" not found.`のエラーが出る

## 原因
node.js,rails/webpacker,webpack,webpack-dev-server,webpack-sliの互換性がない

## 解決策
package.jsonに以下を記載
```
  "engines": {
    "node": "14.16"
  },
  "devDependencies": {
    "webpack": "4.x.x",
    "webpack-cli": "3.x.x",
    "webpack-dev-middleware": "3.x.x",
    "webpack-dev-server": "3.x.x"
  }
```

念の為、webpackerとyarn.lockをアンインストール
```
rm yarn.lock
yarn remove @rails/webpacker
```

念の為、下記のファイルも手動で削除
`config/webpacker.yml`
`bin/webpack`
`bin/webpack-dev-server`

下記の再インストール
```
yarn install
bundle exec rails webpacker:install
```

下記のコマンドでサーバーが立ち上がるようになる
```
bin/webpack-dev-server
```

## デバッグの過程で学んだこと
### webpack / webpacker　とは？
webpackとは、復数のjavascript（とかCSSでとか）ファイルを1つにまとめてブラウザが読み込める形にするもの。webpackは設定用のファイルの記載なども必要で準備が結構面倒…
webpackerは、Railsが準備しているもので設定がもっと簡単（というか本当なら特に設定不要で使えるはず）

※ちなみに今回のデバッグの中で方向性を誤り、webpackerではなくwebpackを直接起動してserverを立ち上げる設定をしてしまいました。設定ファイルの記載内容でもエラーが出やすかったり、バージョンによって記載できる内容が変わるなど、たしかに結構面倒でした。。。

webpackerはその機能をwebpackに依存しているため、webpackやそれに関連するファイル（webpack-dev-serverやwebpack-cliなど）もインストールする必要がある。
webpack関連のファイルはすべてNode.jsにも依存しているため、Node.jsのバージョンとの互換性にも気を遣わないとエラー解決が難しくなる。

### package.json　とは？
Railsのgemfileのようなもの。バージョンを指定してライブラリ？モジュール？をインストールできる。`bundle install`と同じように`yarn install`でインストールを実行可能。

### なぜ互換性のエラーが起きがちなのか
package.jsonに記載していないライブラリも、記載したライブラリが依存しているものなら`yarn install`でインストールしてしまうため。package.jsonに記載する場合はバージョンを指定するが、勝手にインストールされるものはバージョンを指定しないので、勝手に最新版がインストールされることで互換性の問題が発生する原因になりうる。
Paizaのすゝめ

## paizaとは
実行環境構築いらずでブラウザ上でプログラミング言語を実行できます
https://paiza.jp/guide/works

## (自分的に)Paizaでできること
Rubyには便利なメソッドがたくさんあります。
しかし私にとってはそれらをすぐに使いこなすことができませんでした。
そんな私にとってPaizaはメソッドを「知る」・「使う」きっかけになります。
またプログラミングの基礎(条件分岐, 繰り返し処理, 配列処理)も学ぶことができます

## なぜPaizaを使用しようと思ったか
主な理由は2つあります
### コードを書くのが遅い
### 「知っている」けど使いこなせないメソッドたち
Rubyには便利なメソッドが数多く存在しますが、それらを使いこなすことができませんでした
例えば、filterメソッド(配列の中に条件が一致するものがあれば、一致したもののみの配列を返却するメソッド)
1度は使ったことがありますが、なぜ使用したのかやメソッドの理解が足りないためコードを書いているときに使用することができないことが多々ありました
これら2つを改善するために、毎日Paizaに取り組みました

## やってみてどうだったか
似たような問題を反復することで、自分の中でなぜこの操作が必要なのかイメージできるようになり、スムーズに書くことができるようになりました
またレビューの際に、「このメソッドを使用したら簡潔にかける」という指摘がほぼなくなりました
同じように悩んでいる方はぜひやってみてください
Item detailsにArtistを2人ずつ改行しながら出力したーい！

# Item detailsとは
* Columns UI で標準で用意されているパネルの1つ。
* TitleFormatingにより、再生中の曲に設定されているタグ情報を取得してパネルに出力できる。
* 例えば、曲名・作曲・編曲を取得してパネルに出力できる。

```:TitleFormating
// Title用フォント設定
$set_font(%default_font_face%,$add(%default_font_size%,4),bold)
// Titleを出力
 %title%$crlf()$crlf()

// その他情報用フォント設定
$set_font(%default_font_face%,$add(%default_font_size%,3),)
// Composer, Arrangerを出力
' Composer - '%composer%$crlf()
' Arranger - '%arranger%
```
![1_Item detailsとは_モザイク.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2367021/8f210d15-1312-5acd-2013-d5d97608d975.png)

# やりたいこと
**Artistが3人以上の場合、2人ずつ改行しながら出力したい！**
## 動機
* Item detailsの仕様として、TitleFormatingで参照したタグ情報がパネルの横幅に収まりきらないと、適当なところで改行して表示される。
* これによりArtistが3人以上の場合など、**Artist名の途中で改行して表示されるので見栄えが悪い**
* 例えば、"想いよひとつになれ" のArtistのタグ情報をそのまま"%artist%"で参照して出力すると・・・

![2_Artist改行無し_モザイク.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2367021/8efac0b7-a506-8184-d833-4bdf3ab0e78e.png)

**これを2人ずつ改行しながら出力したい・・・！！**

## 目指すべき姿
![2_Artist改行_モザイク.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2367021/bbecbc73-4093-95cf-83d8-d85a091a7cb7.png)

きれい。

# どうしたか
1. Artistのタグ情報を1要素ずつ取得する。
2. 1人ずつ出力して2人出力したら改行する。

## 1. Artistのタグ情報を1要素ずつ取得する
* 指定したタグ情報のn個目の要素を取得できる"$meta(name,n)"構文を使用する。
* $meta(name,n) の詳細はリンク先へ。
[Title Formatting Reference \(日本語訳\)](https://tnetsixenon.xrea.jp/title_formatting.html)
```:TitleFormating 
// Artistのタグ情報を1つずつ、変数ArtistNに代入する
$puts(Artist1,$meta(artist,0))
$puts(Artist2,$meta(artist,1))
$puts(Artist3,$meta(artist,2))
$puts(Artist4,$meta(artist,3))
$puts(Artist5,$meta(artist,4))
$puts(Artist6,$meta(artist,5))
$puts(Artist7,$meta(artist,6))
$puts(Artist8,$meta(artist,7))
```

## 2. 1人ずつ出力して2人出力したら改行する。
* "[...]"構文で変数ArtistNを囲っている理由は、例えばArtistが3人だけのとき、Artist4以降の余計な改行を出力させないようにするため。
* Artistが3人だけのとき、変数Artist4には値が入っていないので[$get(Artist4)]の評価値は空文字列となる。そのためArtist4以降は表示されない。
```:TitleFormating
// 出力用の文字列生成
$puts(outArtistStr,
' Artist   - '[$get(Artist1)][', '$get(Artist2)]
[$crlf()'            '$get(Artist3)][', '$get(Artist4)]
[$crlf()'            '$get(Artist5)][', '$get(Artist6)]
[$crlf()'            '$get(Artist7)][', '$get(Artist8)])

// 出力
$get(outArtistStr))
```

# 感想
* TitleFormatingに配列変数とfor文が無いからさぁ・・・
* あったら教えて欲しいです。

# 参考文献
[Title Formatting Reference \(日本語訳\)](https://tnetsixenon.xrea.jp/title_formatting.html)
Bubble.ioとfirebaseで本格的写真共有ウェブサービスを作ってみた。

https://gallerygo.bubbleapps.io/
↑作ったWebサービスのurlです。

　https://note.com/photo_go/n/n8da40a11ebb8

Noteにもあげましたが、Bubble.ioにて画像共有サービスを作りました。
技術的にはfirebase authを使っています。
ターゲットは一眼カメラを使って本格的に写真を撮る人です。
いわゆる組写真を共有できるサイトとなります。
昔あったcotenというwebサービスをイメージしています。
![Screenshot_20240905-221158.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226764/2b4b9336-1a78-4f99-91d3-f23d5452bc2b.png)
![Screenshot_20240905-221144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226764/44f0b7f9-95e1-8176-224b-a5d624e3bc27.png)
tool_cacheでCacheがHitしない

# Github ActionsでtoolがキャッシュHitしない

カスタムアクションを開発中

以下のコードSwiftのパッケージを持ってきてtoolCacheしているが、次回以降の実行で`toolCachefind` でPathがHitしない
```typescript
  const { platformName, pkgName } = await getPakage("5.10");
  let toolPath = toolCache.find("swift", "5.10");
  if (!toolPath) {
    const { pkgURL, signatureURL } = await getDownloadURL(
      swiftVersion,
      platformName,
      pkgName,
    );
    const { downloadPath, signaturePath } = await downloadSwift(
      pkgURL,
      signatureURL,
    );
    await verifySwift(downloadPath, signaturePath);
    const extractPath = await unpack(downloadPath, pkgName);
    toolPath = await toolCache.cacheDir(
      path.join(extractPath, pkgName),
      "swift",
      swiftVersion,
    );
  }
  const binPath = path.join(toolPath, "/usr/bin");
  core.addPath(binPath);
```

想定動作としては、
1. `toolCache.cacheDir`でtoolCacheのパスにSwiftのディレクトリがコピーされる
1. 次のActions実行時に`toolCache.find("swift", "5.10");`でtoolPathが参照できる

しかし、Swiftはインストールされているが`toolCache.find("swift", "5.10");`でパスが取得できない事象が発生した

## 原因
**セマンティック バージョニングではなかったため発生した**

`tool_cache.find()`のコードを見てみると`isExplicitVersion` でバージョンをバリデーションしている。
`5.10`はセマンティック バージョニングではないため、versionがnullになりうまくCacheHitしない。
```javascript
function find(toolName, versionSpec, arch) {
    if (!toolName) {
        throw new Error('toolName parameter is required');
    }
    if (!versionSpec) {
        throw new Error('versionSpec parameter is required');
    }
    arch = arch || os.arch();
    // attempt to resolve an explicit version
    if (!isExplicitVersion(versionSpec)) {
        const localVersions = findAllVersions(toolName, arch);
        const match = evaluateVersions(localVersions, versionSpec);
        versionSpec = match;
    }
...
```

## 対応策
**`semver.coerce()`でセマンティック バージョニング形式に変換してCache及びfindする**

```typescript
semver.coerce('5.10');
```
【React testing library】type="number"のinputへのuserEvent.typeができない

# はじめに
Reactの自動テストを書いている際に、inputタグのtype=numberへの入力を行った際にうまくnumberの入力ができず困ったため記載します
# 問題
以下のコードで作ったtype=numberのinputに対して「-1」を入力してエラーを出すというテストを書きたかったが、テストでエラー発生
```tsx
  <input type='number' data-testid='time-input' {...register("time", { required: '時間の入力は必須です', min: { value: 0, message: '時間は0以上である必要があります' } })}/>
```
書いたテスト文
```tsx
it('input-error', async () => {
    await act(async() => {
     render(<App />);
    })
    await waitFor(async () => {
      const addButton = screen.getByTestId("add-button");
      await userEvent.click(addButton);
      const timeInput = screen.getByTestId("time-input");
      await userEvent.type(timeInput, "-1");
      await userEvent.click(screen.getByTestId("submit-button"));
      expect(screen.getByText("時間は0以上である必要があります")).toBeInTheDocument();
    });
  })
```

エラー文
```tsx
 Unable to find an element with the text: 時間は0以上である必要があります. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    Ignored nodes: comments, script, style
```

# 原因
上手く入力できておらず、初期値がそのまま入っていた

# 解決方法
```tsx
await userEvent.type(timeInput, "-1");
```
↓
```tsx
fireEvent.change(timeInput, { target: { value: '-1' } });
```
Ubuntu24.04 で failed to start gdm serviceと出た時のエラー解消メモ

## 事象
ubuntuを再起動しようとしたら、 `failed to start gdm service`と出て、起動できなくなった

## 解消法
1. reboot ubuntu
	1. `ctrl` + `alt` + `f3` で別のttyに入る
2. `sudo apt-get install gdm3`
3. `reboot`

## 参考
https://qiita.com/sassy_watson/items/393b9893754b7206205e
https://askubuntu.com/questions/1489129/gdm-service-preventing-boot
https://qiita.com/Lamaglama39/items/768ef0f0a68a3dc7d29b
【TypeScript】ジェネリクス (generics)の利便性を体感する

## ジェネリクスって何？

型の安全性とコードの共通化を両立するために利用されます。
簡単に言い換えると、型を変数として扱えるようにすることと近いです。
本記事では**実際にアプリケーション開発で使えそうな具体例を挙げます**

## 特定の値が存在するか確かめる関数

ReactやNext.jsで活躍すると思います。
特定の値がNullかundefinedの時に、trueを返す関数です。
判定したい値は型が様々（APIのレスポンスデータだったり純粋なstringだったり）かと思いますが、ジェネリクス を使うことで型の分だけ関数を記述することなく済みます。
Nullishについて↓

https://developer.mozilla.org/ja/docs/Glossary/Nullish

```isNullish.ts
function isNullish<Type>(value: Type | null | undefined) {
	if (value === undefined || value === null) {
		return true;
	}
	return false;
}
```
ジェネリクスを使って型を変数のように扱っています。（`<type>`のところです。文字列は任意ですがTが多いです）
上記ですと、valueにはどんな型を入れても事前に型注釈していれば型安全です。(以下の例では型推論を使っているので注釈はしていません)

実際には以下のように利用できます。
```some.tsx
export default function page() {
    const strData = "こんちは";
    	return (
    		<div>
                //利用箇所
    			{!isNullish(strData) && (
    				<p className="text-black">{strData}値は存在したよ</p>
    			)}
    		</div>
    	);
}
```

```some.tsx
export default function page() {
    const data = { hello: "Hello!" };
    	return (
    		<div>
                //利用箇所
    			{!isNullish(data) && (
    				<p className="text-black">{data.hello}値は存在したよ</p>
    			)}
    		</div>
    	);
}
```

このようにisNullish関数を定義しておけば、APIのレスポンスデータを確かめる時からUI内のデータの確認の時までこれ一本で済みコードがスッキリします。
【React Testing Library】 Loadingをテストしたい時に出たエラー Warning: An update to App inside a test was not wrapped in act(...).

# はじめに
ReactのLoadingのテストを書いていた際にエラーが出て、解決まで少し時間がかかったため載せておきます

# 問題
DBからデータを取得するまでLoaging画面を出しているのですが、そのLoadingがちゃんと出ているか確認のテストを書いていたらエラーが出ました。
#### 書いたコード
```tsx
describe("loading", () => {
  it("should render loading", async () => {
    render(<App />);
    expect(screen.getByText("...loading")).toBeInTheDocument();
  });
});
```
#### エラー文
```shell
console.error
    Warning: An update to App inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
        at App (C:\Users\Owner\Documents\app\study-time-record-app-v3\src\App.tsx:37:39)

      89 |         console.error(error)
      90 |       } else {
    > 91 |         setRecords(data)
         |         ^
      92 |         setLoading(false)
      93 |       }
      94 |     }
```
# 原因
調べてみるとStateの変更がきちんと完了されないまま、テストが終了したからエラー(Warning)が出ているとのこと

# 解決方法
Stateの変更が終わるまでテストの終了を待ってあげる
※自分の場合は画面に予測されるデータの情報が出るまで処理を待つコードを書きました
```tsx
describe("loading", () => {
  it("should render loading", async () => {
    render(<App />);
    expect(screen.getByText("...loading")).toBeInTheDocument();
    await waitFor(() => {
      screen.getByText("60時間");
    });
  });
});
```
# 参考
https://bufferings.hatenablog.com/entry/2021/11/18/015809
取得したテーブルデータのマッピング

## やりたいこと
- javascriptで取得したテーブルデータを一部結合して使用したい場合がある
- 大規模な場合はそんなこと不要だが、テーブルを加工せず、複数のテーブルからデータ引用し表示に使いたい場合には外部結合したりして、まるっとtableDataで取得して使いたい
## どうすればできるか
- タイトルに記載しているとおり、tableDataをマッピングする
- マッピングしたら結合している形で使用できるように記述する
- 下記例のように記述することで「リンゴ - 赤」みたいな形に表示できる

- 例：
```
.then((response) => {
                    this.loading = false;
                    this.tableData = response.data.map(item => {
                    return {
                        ...item,
                        fruitsNameColor: item.fruitsName + ' - ' + item.fruitsColor
                    };
                });
```
abstractとinterfaceの違い

# abstractとinterfaceの違い
* **abstract クラス:**
共通の機能を持つ**メソッドやプロパティ**の実装をする。
継承によってその機能を拡張する場合に使います。

* **interface:** 
クラスに対して **特定の契約や構造** を保証する。
複数の契約をクラスに適用したい場合に使います。

:::note info
※　`interface`は構造のみに対して`abstract`は共通処理も構造も定義できる
:::

# abstractの具体例
``` 
// 抽象クラスの定義
abstract class Animal {
    // 抽象メソッド（派生クラスで実装が必須）
    abstract makeSound(): void;

    // 通常のメソッド（派生クラスでも使用可能）
    eat(food: string): void {
        console.log(`The animal is eating ${food}`);
    }
}

// 抽象クラスを継承した具体的なクラス
class Dog extends Animal {
    // 抽象メソッドの実装
    makeSound(): void {
        console.log('Woof! Woof!');
    }
}

// 抽象クラスを継承した別の具体的なクラス
class Cat extends Animal {
    // 抽象メソッドの実装
    makeSound(): void {
        console.log('Meow! Meow!');
    }
}

// 抽象クラスのインスタンス化はできない
// const myAnimal = new Animal(); // エラー: 'Animal' クラスは抽象クラスです

// 具体的なクラスをインスタンス化する
const myDog = new Dog();
myDog.makeSound(); // 出力: Woof! Woof!
myDog.eat('bone'); // 出力: The animal is eating bone

const myCat = new Cat();
myCat.makeSound(); // 出力: Meow! Meow!
myCat.eat('fish'); // 出力: The animal is eating fish

```


# interfaceの具体例

```
interface Animal {
    name: string;
    makeSound(): void;
    move(): void;
}

class Cat implements Animal {
    constructor(public name: string) {}

    makeSound() {
        console.log('Meow! Meow!');
    }

    move() {
        console.log(`${this.name} is moving.`);
    }
}

const myCat = new Cat('Whiskers');
myCat.makeSound(); // 出力: Meow! Meow!
myCat.move();      // 出力: Whiskers is moving.

```
VirtualBoxのKaliLinuxのNetworkManagerでTryHackMeにVPN接続できなかった話

`openvpn`コマンドでは接続できるが、パネルからの、NetworkManagerでは接続できなかったのを解決したのでメモ。

https://tryhackme.com/dashboard

# 環境
ホストOS: Windows11 Home
VitrualBox: VirtualBox 7.0.20
ゲストOS: kali-linux-2024.2-virtualbox-amd64

# エラー状況
エラーが起きた手順を説明します。
まずはTryHackMeサイトから`.ovpn`ファイルをダウンロードします。
https://tryhackme.com/r/access
![スクリーンショット 2024-09-04 064053.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/8f75254f-3e4b-1ede-8152-e2913c697d12.png)
KaliLinuxとの共有フォルダに移動させ、`openvpn`コマンドで実行すると正常に接続でき、パネルにIPが表示されます。
```console
$ sudo openvpn xxxxxxxx.ovpn
```
![スクリーンショット 2024-09-04 065608.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/15160df8-520d-3414-887f-4da7c3b54144.png)
しかしながら、パネルのNetworkManagerから`Add a VPN connection...`で`.opvn`ファイルを追加するとエラーになります。
`VPN Connections` → `Add a VPN connection...`
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/abd00084-b72f-f9f8-e6b7-16d2cae70bd8.png)
`Import a saved VPN configuration...`を選択して`Create...`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/cef0fb16-ec23-4cdd-b812-9d27cb712442.png)
`.ovpn`ファイルを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/a2a4b696-5bbc-4b62-be04-1b55de042331.png)
設定は変更せずに`Save`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/359ba257-fdcc-a3bd-a9c7-8923e681882b.png)
追加した接続を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/96e87a8d-f1e2-f074-6c88-063dc4deb9c8.png)
IPが表示されたり消えたりする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/28fddd0c-6b18-f1fc-db64-94337b9dc505.png)
ログを確認すると、`AES-256-CBC`が許可されていませんでした。
```console
$ journalctl -u NetworkManager.service
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/80ccc9c1-d04e-2662-05dd-96c26400da69.png)
エラー部分
```
Sep 03 18:15:26 kali nm-openvpn[1909729]: Error: negotiated cipher not allowed - AES-256-CBC not in AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
Sep 03 18:15:26 kali nm-openvpn[1909729]: OPTIONS ERROR: failed to import crypto options
Sep 03 18:15:26 kali nm-openvpn[1909729]: Failed to open tun/tap interface
```


# 修正手順
## 1\. OpenVPN設定ファイルをインポート
ダウンロードした`.ovpn`ファイルをインポートします。
すでにエラーが起きている状態なら次のステップを参照してください。
## 2\. VPN接続設定ファイルの編集
接続を作成すると`.nmconnection`ファイルが作成されます。
```console
$ ls /etc/NetworkManager/system-connections
'TryHackMe VPN.nmconnection'
```
対象の接続名の`.nmconnection`ファイルを編集します。
```console
$ sudo nano '/etc/NetworkManager/system-connections/TryHackMe VPN.nmconnection'
```
`[vpn]`セクションに`cipher=AES-256-CBC`および`data-ciphers=AES-256-CBC`を追加します。
```diff
[vpn]
...
+ cipher=AES-256-CBC
+ data-ciphers=AES-256-CBC
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/07e34a1b-d0c9-a31c-bbd2-b36be4c9724a.png)


## 3\. NetworkManagerの再起動
NetworkManagerを再起動します。
```
$ sudo systemctl restart NetworkManager
```

これで、無事に接続できるようになりました。
Pythonでのオプショナル型の使い方とスクレイピングの実装

# はじめに
Pythonでは、オプショナル型（Optional）を用いることで、関数やメソッドが値を返す or 返さないといったケースを安全に扱うことができます。
スクレイピングのようなデータ取得処理では、取得できるデータが不確定な場合もあります。
そのような場合、オプショナル型を使うとコードの安全性と可読性が向上します。

# オプショナル型とは

Pythonの標準ライブラリ `typing` モジュールには、`Optional` 型が用意されています。
`Optional` は、「値があるかもしれないし、`None` かもしれない」ことを示すための型です。

# 使用例

`Optional` は次のように使用します：

```python
from typing import Optional

def get_username(user_id: int) -> Optional[str]:
    if user_id == 1:
        return "JohnDoe"
    else:
        return None

# 使用例
username = get_username(2)
if username is not None:
    print(f"Username: {username}")
else:
    print("User not found")
```
この例では、`get_username` 関数が文字列型 (`str`) もしくは `None` を返すことがわかります。
関数の戻り値が `None` である可能性を型として明示することで、開発者は `None` チェックを忘れずに行うことができます。

# スクレイピングにおけるオプショナル型の利用
スクレイピングを行う際には、ページから特定の要素を取得することが目的となりますが、要素が存在しない場合も考慮する必要があります。
ここで `Optional` を利用することで、コードの安全性を高めることができます。

以下の例では、`requests` と `BeautifulSoup` を用いて、Webページからタイトルを取得する簡単なスクレイピングを行います。

## 必要なライブラリのインストール
まず、`requests` と `BeautifulSoup` をインストールしていない場合はインストールします：
```python:bash
pip install requests beautifulsoup4
```

サンプルコード
```python:python
import requests
from bs4 import BeautifulSoup
from typing import Optional

def fetch_page(url: str) -> Optional[str]:
    """指定したURLからページのHTMLを取得する関数"""
    try:
        response = requests.get(url)
        response.raise_for_status()  # ステータスコードがエラーの場合は例外を発生させる
        return response.text
    except requests.RequestException as e:
        print(f"Error fetching the URL: {e}")
        return None

def get_title(html: Optional[str]) -> Optional[str]:
    """HTMLからタイトルを取得する関数"""
    if html is None:
        return None

    soup = BeautifulSoup(html, 'html.parser')
    title_tag = soup.find('title')
    return title_tag.get_text(strip=True) if title_tag else None

if __name__ == "__main__":
    url = "https://example.com"
    html = fetch_page(url)
    title = get_title(html)

    if title:
        print(f"Page Title: {title}")
    else:
        print("Title not found or failed to fetch page.")
```

## コードの説明
1. `fetch_page` **関数**: 指定されたURLからHTMLを取得します。`requests`を使ってHTTPリクエストを行い、成功した場合はページの内容を文字列として返します。
リクエストに失敗した場合は `None` を返します。この関数の戻り値は `Optional[str]` 型です。

1. `get_title` **関数**: HTML文字列を受け取り、BeautifulSoupを使ってページのタイトルを取得します。
HTMLが `None` の場合や、タイトルタグが見つからない場合は `None` を返します。
この関数の戻り値も `Optional[str]` 型です。

1. `if __name__ == "__main__":` **ブロック**: 実際のスクレイピングの実行部分です。
URLを指定してページのタイトルを取得し、結果に応じて適切なメッセージを表示します。

# なぜオプショナル型を使うのか？
このスクレイピングの実装では、オプショナル型を使用することで、次の利点があります：

- **エラー処理が簡潔になる**: 関数が None を返す可能性を明示することで、呼び出し側で必ず `None` チェックを行うように促します。
- **コードの可読性が向上する**: 戻り値の型が明示されているため、他の開発者がコードを読む際に関数の意図を理解しやすくなります。
- **型ヒントによる開発支援**: IDEやエディタが型チェックを行ってくれるため、実装ミスを早期に発見できます。

# まとめ
Pythonのオプショナル型（`Optional`）を使うことで、スクレイピングのようなデータの有無が不確定な状況でのプログラムの安全性を向上させることができます。

Webからのデータ取得処理では、存在しない要素や取得エラーに対処するために、オプショナル型を活用して例外的なケースを効果的に扱えます。
FSx for Windows File Serverをファイルエクスプローラーから利用する方法

## はじめに
今回は、FSx for Widows File Serverをファイルエクスプローラーから利用する方法を2つ紹介します。

## 前提条件
### FSxとADの連携
FSxをADに参加させる必要があります。
AWS Managed Microsoft ADを利用している場合は、以下の様にディレクトリを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/b7e42e88-d85e-b243-ba4a-321e627aac29.png)

自己管理型のADを利用している場合、以下の様にドメイン名、DNSサーバのIPアドレス、サービスアカウントのユーザー名、サービスアカウントのパスワードを入力する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/66be4f4a-1096-2669-025f-10b9b01afd7c.png)

サービスアカウントをADで作成する必要があります。
このとき、ADにてFSx参加専用のOUを作成することを推奨します。
そして、FSx用のOUの制御を委任するためのグループを作成し、その配下にサービスアカウントとなるユーザを作成します。

### ネットワーク
クライアントとFSx、ADが通信できるようファイアウォールやセキュリティグループ等の設定を実施することも必要です。

## 利用方法①クライアントにFSxをマウント
### コマンドプロンプトから設定する場合
クライアントのコマンドプロンプトから以下のコマンドを実行します。

```net use Z: \\(FSxのDNS名)\share```

※「Z:」は、使用可能な他のドライブ文字に置き換えて問題ありません。


### エクスプローラーから設定する場合

コマンドプロンプトを利用しなくとも、マウントすることは可能です。
エクスプローラーのネットワークを右クリックし、「ネットワークドライブの割り当て」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/1f7c9577-0165-acab-08fe-cdf951acd55d.png)


ドライブを選択し、フォルダーに ```\\(FSxのDNS名)\share``` と入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/5dc45392-d477-a545-05b5-efa1db3ad367.png)




## 利用方法②パスでアクセス
 ```\\(FSxのDNS名)\share ``` の形でエクスプローラーからアクセスすることが可能です。

まず、ファイルエクスプローラーの窓に「\\(FSxのDNS名)\share」を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/3f8a4450-f126-6be1-e6b9-29148307051e.png)

ネットワーク資格情報として、ユーザとパスワードを入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/bc777a78-2cfe-a376-019d-3d2ee5ac6857.png)

ファイルアクセスに成功します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115411/f0bc9e3c-b613-f7ae-e410-c5bfab240cf6.png)


## 最後に
クライアントからFSx for Windows File Serverへ接続する際にはマウントは必須だと思っていたのですが、②の方法でマウントなしでアクセス可能だとわかりました。

ファイルアクセスで何かトラブルが起きた際は以下の記事も参考にしてください。

https://qiita.com/utsunomiya_ff/items/634778641f8ccc0578e8
YouTube等の動画共有サービスからVJ素材をダウンロードするには

VJとはビデオジョッキーのこと。VJで使う動画素材をYouTubeなどの動画共有サービスからダウンロードする方法を書きます。

# yt-dlpとは

動画ダウンロードツールで、YouTubeやtiktokなどの動画共有サービスから動画をダウンロードするときに標準的に使われるツールです。
公式ページを見ると対応サイトは非常に多くて、なんと1,800くらいあります。
一例を挙げると、

- Youtube
- ニコ動
- Vimeo
- Dailymotion
- BiliBili
その他多数…

詳しくはこちらに対応サイトのリストがあります。

https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md

# Homebrewをインストール
Homebrewとはパッケージマネージャーです。Homebrewを使うことでいろんなアプリケーションを簡単にインストール、アップデートすることができます。

ホームページにアクセスして真ん中あたりのコマンドをコピー
![スクリーンショット 2024-07-09 19.38.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588661/4cfa3b01-0fe1-9d0e-f2a9-29d47231d174.png)

https://brew.sh/ja/

Launchpadを開き「その他」の中から「ターミナル」をクリックして起動します
![original.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588661/508cbdd4-12b9-9120-feab-c9fe52673094.png)

ターミナルを起動したらコピーしたコマンドを貼り付けてEnterを押す
![スクリーンショット 2024-07-09 19.48.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588661/4534b487-54be-81ca-690b-3f8e8a19bbc9.png)

https://www.pc-koubou.jp/magazine/79193

## パスを通す

しばらくするとインストールされて、下の画像のとおりメッセージが表示される
その「Next steps」にあるとおりコマンドを実行する
![スクリーンショット 2024-07-09 20.34.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588661/60f1e621-d26a-7fd6-34a4-ca8957fe010e.png)

`brew help`と入力してヘルプ画面が出てきたら、インストール成功です

# yt-dlpをインストール

ターミナルで下記の通り実行します
```sh
brew install yt-dlp
```

# ffmpegをインストール

yt-dlpの動作にはffmpegも必要なので、ターミナルで下記のとおり実行してインストールします
```sh
brew install ffmpeg
```

# 使い方 基本編

最も簡単な使い方です。ターミナルでこのように入力します。
ダブルコーテーションがないと動かないので、下記のとおり忘れずに入力してください。
```sh
yt-dlp "[動画のURL]"
```

# 複数ファイルを一括ダウンロード

こちらの記事をご覧ください。

https://qiita.com/Bacalhau/items/c49769f75356c2090656

# yt-dlpを使うための便利なシェルスクリプト

いちいちコマンドやらオプションやらを入力するのは面倒いので、それを解決するスクリプトを作った。

https://qiita.com/HXYoUGZ/items/8315f9c4825f98e8049f
オブジェクト指向をスクレイピングを題材に説明

# オブジェクト指向とは
オブジェクト指向プログラミング（以下OOP）は、プログラムの設計と構造を改善するための強力な手法です。
特にコードの再利用性、拡張性、保守性を向上させるための効果的な手段となります。
本記事では、1ファイル1クラスの原則を用いたPythonによるオブジェクト指向設計で、スクレイピングを実装する方法を解説します。

# オブジェクト指向プログラミングの基本概念
OOPには以下のような基本概念があります：

- **クラス（Class）**: オブジェクトの設計図であり、データ（属性）と振る舞い（メソッド）を定義します。
- **オブジェクト（Object）**: クラスを基に生成されたインスタンスです。
- **継承（Inheritance）**: 既存のクラスを基に新しいクラスを作成し、機能を引き継ぐことができます。
- **ポリモーフィズム（Polymorphism）**: 同じインターフェースを使用しながら異なるクラスで異なる実装を持たせることができます。
- **カプセル化（Encapsulation）**: オブジェクトの内部状態を隠蔽し、外部からのアクセスを制御します。

これらの概念を理解した上で、Pythonによるスクレイピングのオブジェクト指向実装を見ていきましょう。
# 1ファイル1クラスの設計方針
OOPの設計では、**1ファイル1クラス**の原則を守ることで、以下のような利点が得られます：

- **可読性の向上**: ファイルがシンプルになり、どのファイルにどのクラスがあるかが一目瞭然になります。
- **保守性の向上**: クラスの変更が必要な場合、影響を受けるファイルは1つだけです。
- **再利用性の向上**: 特定のクラスを別プロジェクトに簡単に移動できます。
- **バージョン管理のコンフリクト回避**: 1つのファイルで複数人が作業しても競合が少なくなります。

# スクレイピングのためのクラス設計
今回のスクレイピング実装では、次のような構成でクラスを設計します：

- `Scraper` **クラス**: 基本的なスクレイピング機能を提供する抽象クラス。
- `TableScraper` **クラス**: テーブルデータを抽出する機能を持つ具象クラス。

この設計に従い、各クラスを個別のファイルに定義します。

## `scraper.py`（Scraperクラス）
`Scraper` クラスは、基本的なスクレイピングの骨格を提供する抽象クラスです。

```python:scraper.py
import requests
from bs4 import BeautifulSoup
from abc import ABC, abstractmethod

class Scraper(ABC):
    def __init__(self, url):
        self.url = url
        self.soup = None

    def fetch(self):
        """URLからHTMLを取得してBeautifulSoupオブジェクトに変換する。"""
        try:
            response = requests.get(self.url)
            response.raise_for_status()
            self.soup = BeautifulSoup(response.content, 'html.parser')
        except requests.exceptions.RequestException as e:
            print(f"Error fetching the URL: {e}")

    @abstractmethod
    def parse(self):
        """サブクラスでオーバーライドするためのメソッド。"""
        pass
```

## `table_scraper.py`（TableScraperクラス）
`TableScraper` クラスは、`Scraper` クラスを継承し、テーブルを抽出する具体的な機能を提供します。

```python:table_scraper.py
from scraper import Scraper

class TableScraper(Scraper):
    def __init__(self, url):
        super().__init__(url)

    def parse(self):
        """テーブルデータを抽出して表示する。"""
        if not self.soup:
            print("Soup object is not initialized. Please run fetch() first.")
            return

        tables = self.soup.find_all('table')
        for i, table in enumerate(tables, 1):
            print(f"Table {i}:")
            rows = table.find_all('tr')
            for row in rows:
                cols = row.find_all(['td', 'th'])
                cols = [col.get_text(strip=True) for col in cols]
                print("\t".join(cols))
            print("\n")
```

## `main.py`（メインプログラム）
`main.py` ファイルでは、クラスをインポートし、実行のためのコードを記述します。

```python:main.py
from table_scraper import TableScraper

if __name__ == "__main__":
    url = "https://example.com"  # スクレイピングしたいページのURLを指定
    scraper = TableScraper(url)

    # HTMLを取得
    scraper.fetch()

    # テーブルをパースして表示
    scraper.parse()
```

# まとめ
**1ファイル1クラス**の設計は、オブジェクト指向プログラミングの良さを最大限に引き出す手法です。
スクレイピングのようなプロジェクトでは、複数の異なるデータ構造や処理を扱う必要があります。
クラスを独立させることでコードの見通しが良くなり、保守や再利用がしやすくなります。

今回紹介したスクレイピングの実装例を参考に、OOPと1ファイル1クラスの原則を活用して、より洗練されたPythonプログラムを作成してみてください。
sympyのLineのslopeの単位を調べてみた。

A line is declared with two distinct points or a point and slope as defined using keyword slope
.

https://docs.sympy.org/latest/modules/geometry/lines.html#sympy.geometry.line.Line2D

```python
from sympy import *
print("#",Line(Point(0,0),slope=1).intersection(Line(Point(0,1),Point(1,1))))
# [Point2D(1, 1)]
```
Remixで_index.tsxにloader関数を実装したくない

# 結論
`_index.tsx`では`/home`へのリダイレクトのみ実装して、`/home`で機能の実装を行なう。

```typescript
import { redirect } from "@remix-run/node";

export const loader = async () => {
  return redirect("/home");
};

export default function Index() {
  return null;
}
```

# 経緯など
作成中のWebアプリで、ホームページに表示させる機能を迷っていて、後で丸ごと変更するかもしれないという状況でした。そのため、`_index.tsx`にloader関数を実装して、取得したデータを子コンポーネントに渡して～というような実装にすると、後で面倒なことになるかもなと思いこのような実装にしました。

`_index.tsx`をリダイレクトするだけにしておくことで、ホームページ変更の際はリダイレクト先（もしくはそのファイル）を変えればいいだけなので、メンテナンスが楽になります。

サイトURLをホームページにしたくて、色々小細工をしようとしましたが、`_index.tsx`とloader関数の仕様上この方法に落ち着きました。

もし、他にいい方法があったらコメントで教えて下さい。
Java Gold 例題 比較演算

# 問1

次の配列を比較する式`insert code`に適切なコードを書いてください。
ただし、配列の要素が同じ場合、`true`を返してください。
```java
int[] numA = {1, 2, 3};
int[] numB = {1, 2, 3};
boolean isSameArrays = /* insert code */
```

<details><summary>解答</summary>
例

```java
Arrays.equals(numA, numB);
```
配列同士の比較で`==`または`numA.equals(numB)`の使用は、配列の中身ではなく参照の比較となり、`false`を返します。
予期せぬ結果を招く可能性があるので、あえて参照の等価性を比較する場合を除き、使うべきではありません。

:::note
[`JEXP02-J. 配列の中身を比較するには2引数の Arrays.equals() メソッドを使う`](https://www.jpcert.or.jp/java-rules/exp02-j.html)
:::

</details>

<br>

# 問2
出力を答えてください。

`Studentクラス`
```java
class Student{
	private String name;
	private Integer num;
	Student(String name, Integer num){
		this.name = name;
		this.num = num;
	}
	String getName() {return name;}
	Integer getNum(){return num;}
	public String toString() {return name;}
}
```
`Main`クラス
```java
Comparator<Student> myComparator = new Comparator<>() {
    @Override 
    public int compare(Student studentA, Student studentB) {
        Integer a = studentA.getNum();
        Integer b = studentB.getNum();				 
        return b < a ? 1 : (a == b ? 0 : -1);
    }
 };
 
 List<Student> students = new ArrayList<>();
 students.add(new Student("AIOI", 1000));
 students.add(new Student("INOUE", 1000));
 students.add(new Student("URABE", 1000));
 
 students.stream().sorted(myComparator).forEach(System.out::println);
```
<details><summary>解答</summary>

```
URABE
INOUE
AIOI
```
Integer型での比較演算子が問題です。
`a == b`では`Integer`型の比較をしていますが、参照の等価を返すので`false`を返します。



三項演算子により、`-1`を返すので、`students`の順番が入れ替わります。

:::note alert
より詳細な注意点について、問3の解答も確認することを推奨します
:::

</details>



# 問3
次のコードの出力について正しい選択肢を選んでください。
```java
List<Integer> list = new ArrayList<>(Arrays.asList(100, 200));
List<Integer> list2 = new ArrayList<>(Arrays.asList(100, 200));
int count = 0;
for(int i = 0; i < 2; i++) {
    if(list.get(i) == list2.get(i)) count++;
}		 
System.out.println(count);
```
1.  2
1.  1
1. コンパイルエラー
1. 実行時例外
1. 実行時エラー
1. 状況による


<details><summary>解答</summary>

正解: 6 状況による


`Integer`クラスについての問題です。プリミティブ型の`int`では`==`での比較は正常に行われます。
しかし、ラッパークラスである`Integer`では、JVMの実装によっては等価演算子による比較で、等価にならない可能性があります。
Integerクラスでは-128 ~ 127の範囲の整数について、キャッシュされることが保証されています。
その条件でのコードの出力結果は1になります。

よって選択肢2の出力「1」も状況にもよりますが、正解になります。

> ボクシング変換の対象となる値 p が true, false, byte, \u0000 から \u007f までの範囲にある char, あるいは -128 から 127 までの数値となる int や short である場合, 任意の p に対する2つのボクシング変換結果を r1 と r2 とする。この場合, 常に r1 == r2 が成立する。

:::note
[`EXP03-J. ボクシングされたプリミティブ型の値の比較に等値演算子を使わない`](https://www.jpcert.or.jp/java-rules/exp03-j.html)
:::

</details>

---

https://qiita.com/T-ngtj/private/df254aacd05be698199a
[Ruby on Rails]enumerize gemでoptionsを絞り込みたい場合

## enumerize gemについて

Ruby on Railsでenumを使いたい時に便利なGem
https://github.com/brainspec/enumerize

ざっくり使い方

```ruby
class User
  extend Enumerize

  enumerize :role, in: [:user, :admin, :staff]
end
```

## 本題: optionsを絞り込みたい場合

enumerizeのoptionsを使用してkey, valueの構造を取得する場合に任意の項目を除外または指定した項目だけを取得したい場合には以下のように指定します。

### 除外したい場合

```ruby
User.status.options(except: [:admin])
# => user, staffが取れる
```

### 指定した項目だけ取得したい場合

```ruby
User.status.options(only: [:user])
# => userのみが取れる
```

## まとめ

以上、雑ですが忘れそうなのでメモ残します。

ちなみにライブラリの実装追いました。
この辺でオプションの使い方が分かります。
https://github.com/brainspec/enumerize/blob/master/lib/enumerize/attribute.rb#L66-L70
【AWS認定合格記】AWS sysOps Administrator アソシエイト(SOA-C02)

## はじめに
:::note warn
受験は今から約半年も前のことになりますが、当時の勉強方法などの備忘録を記載しています。
:::


軽く自己紹介すると、、
◆学部卒(非情報系)
◆新卒でSIerに入社し、3年目。
◆取得資格
| 資格名 | 取得日 |
|:-----------|:-----------|
| 基本情報技術者 | 2021年11月  |
| AWS クラウドプラクティショナー | 2023年2月 |
| AWS ソリューションアーキテクトアソシエイト | 2023年7月 |
| AWS ソリューションアーキテクトプロフェッショナル | 2024年3月 |
| AWS デベロッパーアソシエイト | 2024年3月 |
| AWS sysOps Administrator アソシエイト | 2024年4月 |


:::note info
sysOpsAdministratorアソシエイトを取得するまでは、業務ではAWSに携わったことはありませんでした。
:::



## 勉強方法
使用した問題集は、**CloudTechのみ**でした。

 https://kws-cloud-tech.com/

個人的なCloudTechの使い方は以下。
　①まずは、CloudTechの問題に目を通してみる。
　②分からないワードを調べる。
　③答えを見てなぜその答えなのか、解説を読む。分からないところは調べる。
　④全ての問題で①〜③を行う。
　⑤実際に答えを見ずに解けるか確認する。



## 勉強期間
合格までに要した期間は**約3週間**。

平日：約3時間〜4時間
休日：約7時間~9時間

ざっくりの計算で**約100時間ほど**でした。



## 試験当日

| 時間 | 流れ |
|:-----------|:-----------|
| 10:00 | 試験開始|
| 12:00 | 試験終了|
| 19:18 | 合格通知メール届く|　


試験は140分間ですが、ほぼギリギリまで時間を使いました。

試験終了後の感覚としては、clooudtechに似た問題は数問だけで、半分受かったような半分ダメだったような、、という感じでした。難易度は、DVAより少し難しかったように感じます。

https://aws.amazon.com/jp/certification/certified-sysops-admin-associate/

## モチベーションの保ち方
DVA受験同様、当時4月以降に次のPJが決まるため、PJを上司が決めるまでになるべく多く資格を取って、少しでもAWSのやる気があるアピールがしたかったので、取らないと！と焦っていました。
その焦りがモチベーションになったのだと思います。

## 受験〜合格しての所感
### 5つ目合格！目標達成！
当時、4月中にAWS資格は最低でも5つは取りたいと自分で目標を決めていたため、それが達成できてとても安心しました。

::: note info
AWSの資格は情報処理試験と違っていつでも受けられるので、**いつまでに・どの資格を取る！と目標を決めること**が大事だと感じました。
:::
Git hub プロフィール編集してみました

# はじめに
今回はプロフィールを編集してみたので写真と併せて何を参考にどんな風にしたのかお伝えできればと思います。


## まずはリポジトリ等準備

https://zenn.dev/a_ichi1/articles/0411396e6b887d

- 早速上記記事を参考に進めていきます

- 最初必要があればリポジトリを作成とのことだったので作成しました
（すでに自分の名前でいつ作ったかわからないものがありましたが、Github画面上で編集することができなかったので一度削除してから作り直しです。）

- 👇下の画面でチェック欄へ✅忘れずに！！

[![Image from Gyazo](https://i.gyazo.com/3b4e5f4e16e3ee84f483c8a1692998f4.png)](https://gyazo.com/3b4e5f4e16e3ee84f483c8a1692998f4)


- 👇無事完成！

[![Image from Gyazo](https://i.gyazo.com/6a773d657a014844a4a723568e51f83f.png)](https://gyazo.com/6a773d657a014844a4a723568e51f83f)


## Readmeを編集していく

https://github.com/anuraghazra/github-readme-stats

https://github.com/ryo-ma/github-profile-trophy

- ここから一番初めの記事と公式？を参考に進めていきます
- 公式をみないでも、一番初めの記事だけで完成します
- なので流れは割愛して、はい、完成👇

[![Image from Gyazo](https://i.gyazo.com/7bac563f7bb2e61c70afd4c385829903.png)](https://gyazo.com/7bac563f7bb2e61c70afd4c385829903)



## サマリーカード

https://paiza.hatenablog.com/entry/2022/07/06/160000

https://github-profile-summary-cards.vercel.app/demo.html

- サマリーカードについて、公式では「トークンを取得して、ファイルを作成して、actionを実行して、」と結構めんどくさいですし、私自身、なぜかうまくいかなかったので上の記事とサイト参考に。
- ご自身のGithubユーザー名を入力すれば、サマリーカードができてしまいます！
- 一応、公式と途中の私の経過写真を記憶のためにも載せておきます👇

https://github.com/vn7n24fzkq/github-profile-summary-cards/wiki/#add-personal-access-token-to-repo


[![Image from Gyazo](https://i.gyazo.com/0ae7d480d274aa21c237a3377bdf715f.png)](https://gyazo.com/0ae7d480d274aa21c237a3377bdf715f)

[![Image from Gyazo](https://i.gyazo.com/8b3d92e0625f2f2bc5a426f6a05aa50a.png)](https://gyazo.com/8b3d92e0625f2f2bc5a426f6a05aa50a)


## バッジについて

https://qiita-badge.apiapi.app/

https://qiita.com/mikkame/items/f2c60d9caf8a8e38ec50

https://zenn.dev/yutakatay/articles/kirakira-github-profile

- バッジについても上記を参考にすればほぼ完成！
- ご自身のユーザー名に変えればいいだけです。

# さいごに
サマリーカードは公式と一番最初の記事の通り行うと失敗する確率が高いのかもしれません。生地が若干古く、今のGithubとの配置が異なっている事と関係しているのかもしれません。
コピペが一番楽でした。
今回の記事が何か参考になれば幸いです。
ChainlitのVSCodeデバッグ用launch.json

[Chainlit](https://docs.chainlit.io/get-started/overview)はチャット型AIアプリを構築するためのオープンソースのPythonパッケージで、生成AIを活用したチャットアプリを作ることができます。
Productionでの活用が想定されており、生成AIによる回答作成の中間処理を表示できたり、LangChain/Autogen/Haystackなど生成AI関連で人気のあるフレームワークをChainlitに統合する機能もあります。
Chainlitでアプリを開発するためにVSCodeのデバッグ機能を試しました。

こちらの記事を参考にさせていただきました。

https://qiita.com/coleyon/items/a37ac950661e64a1d3ff

# launch.json(VSCodeのデバッガ起動設定ファイル)の作成

VSCodeを起動し、.vscode/launch.jsonを作成して以下の内容を記入する。
```launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "debug",
            "type": "debugpy",
            "request": "launch",
            "module": "chainlit",
            "console": "integratedTerminal",
            "envFile": "${workspaceFolder}/.env",
            "env": {
                "PYTHONPATH": "${workspaceFolder}",
            },
            "args": [
                "run",
                "${file}",
                "-w"
            ]

        }
    ]
}
```

# デバッガーによるサーバーの起動
VSCodeで実行したいファイルを開き、左サイドバーのRun and Debug(または実行とデバッグ）をクリックする。
「Run and Debug」の右横の緑三角のボタンをクリックすると、.envファイルの設定を読み込みつつ、デバッガーによりサーバーが起動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248948/941a2f1d-3310-8131-d047-af878c0df3c9.png)

以上です。
企業公式サイトのおもしろソースコード　隠しアスキーアート10選！–おつまみとしてのソースコード第1皿–情報システム部門を刺激するメディア「情シスのじかん」より

「情シスのじかん」は、情報システム部門のプロフェッショナルを対象としたメディアです。実務に役立つノウハウや革新的なアイデアを提供し、学びとネットワーキングの場を提供することを目指しています。最新の技術動向やベストプラクティス、成功事例を通じて、情シス担当者のスキルアップをサポートします。

ここで、Qiitaの読者の皆様向けに、「情シスのじかん」で公開された記事をピックアップ＆サマリ紹介します！Qiitaは技術者向けの情報共有プラットフォームとして、より実践的で具体的な技術情報を提供する場です。情シスのじかんは、特に情報システム部門に特化した内容を中心にしていますが、両者の強みを活かして、プロフェッショナルの皆様に有益な情報をお届けします。

### 企業公式サイトのおもしろソースコード　隠しアスキーアート10選！–おつまみとしてのソースコード第1皿
![14ceab7b133923ee39c026eb9f85889f.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816554/0af4a879-be97-d771-fea8-1f335d2724c7.jpeg)

ITエンジニアであれば、企業サイトのソースコードはつい見てしまうもの。情シスのじかんの読者のみなさんも、お気に入りのサイトのソースコードが気になってチェックしてしまった、という経験があるのではないでしょうか？ユニークで面白い、意外なアイデアが詰め込まれているソースコードの世界をおつまみ感覚で紹介するのが、情シスのじかんの 「おつまみとしてのソースコード」です！週末も近づき、ちょっと一息つきたくなる木曜日の夕方にお届けしていきます。

第一回は「隠しアスキーアート」。チェックしたソースコードの中に絵やメッセージが隠されていたら、驚いてしまいますよね。でも実は、ソースコードにアスキーアートが隠されているサイトも存在するのです。

https://josys.wingarc.com/source-code-as-a-snack-001

### 情報システム部門を刺激するメディア「情シスのじかん」とは？
![OGP_情シスのじかん.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816554/1f0ea482-2835-d6bd-4a8e-5ec733e466eb.png)

初めまして、『情シスのじかん』です。
近日遂に、日本中の情シス部門のあなたを刺激するメディアが発足します！🚨
さぁ、テクノロジーを飼い慣らし、仕事や生活の質を向上させ、一緒に未来を切り拓きましょう。皆様の生活リズムに合わせた情報発信で、常に寄り添い、共に未来を切り拓くためのメディアです。

ぜひ、情報システム部門の皆様の活動の取材をさせてください。

https://josys.wingarc.com/about