OmniAICreator/Qiita-1.07M huggingface dataset:
to respond to `has_tag?

```
Failure/Error: expect(@response.body).to have_tag(:div)
       expected "<!DOCTYPE html>\n<html>\n<head>\n.....</html>\n" to respond to `has_tag?
```
下のドキュメントを読んで実行したが失敗し続けた。

https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers#have_tag-instance_method:~:text=permalink-,%23have_tag(tag%2C%20options%20%3D%20%7B%7D)%20%7B%20...%20%7D%20%E2%87%92%20Object,%3D%3E%20%7B%20%3Aclass%20%3D%3E%20%27two%20one%27%20%7D),-Parameters%3A

# 解決
https://qiita.com/eielh/items/36c9bbbb998ec56611bf

上の記事で解決できた。
`rspec-html-matchers`をインストールが必要だった。configも設定する
```rb
gem 'rspec-html-matchers'
```
https://github.com/kucaahbe/rspec-html-matchers

# このメソッドがどこのライブラリにあることを意識する必要があった
>Ruby のライブラリは主に RubyGems.org に gem として置かれています。

https://www.ruby-lang.org/ja/libraries/#:~:text=Ruby%20%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AF%E4%B8%BB%E3%81%AB%20RubyGems.org%20%E3%81%AB%20gem%20%E3%81%A8%E3%81%97%E3%81%A6%E7%BD%AE%E3%81%8B%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82

>Libraries » rspec-html-matchers (0.10.0) » Index (R) » RSpecHtmlMatchers
Module: RSpecHtmlMatchers
Defined in:
lib/rspec-html-matchers.rb

https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers#have_tag-instance_method:~:text=Libraries%20%C2%BB%20rspec,html%2Dmatchers.rb

# have_tagメソッドの説明

https://www.rubydoc.info/gems/rspec-html-matchers/RSpecHtmlMatchers#have_tag-instance_method:~:text=permalink-,%23have_tag(tag%2C%20options%20%3D%20%7B%7D)%20%7B%20...%20%7D%20%E2%87%92%20Object,%3D%3E%20%7B%20%3Aclass%20%3D%3E%20%27two%20one%27%20%7D),-Parameters%3A
Flow Element: Wait for Amount of Time 


+ [一定期間待機](https://help.salesforce.com/s/articleView?id=sf.flow_ref_elements_wait_for_amount_of_time.htm&type=5)

+ [Salesforce Flow の待機要素とは何ですか?](https://www.avenoir.ai/post/what-is-the-wait-element-in-salesforce-flow)

# 条件を待つ

「条件待ち」要素は一時停止要素に代わるもので、両者にほとんど違いはありません。この要素を使用して、特定の時間まで、またはプラットフォーム イベント メッセージまで待機できます。以前の一時停止要素と同様に、ベース時間、オフセット数、単位を入力して再開時間を設定できます。さらに、待機条件を設定でき、プラス ボタンをクリックして複数の待機構成を追加できます。

# Wait Element を使用する理由は何ですか?

+ Sleep/pause/wait は Apex では使用できません。つまり、スレッドを一時停止することはできません。

> + [Apex コードのスレッド スリープ](https://ideas.salesforce.com/s/idea/a0B8W00000GdWWdUAN/thread-sleep-for-apex-code)

スレッドをスリープ状態にする機能は提供予定はありません。マルチテナントの世界では、スリープ状態のスレッドは他の顧客が使用できないスレッドです。これが何度も発生するのであれば問題ありません。しかし、不適切に使用されると、サービスに悪影響を与える可能性があります。

非常に特殊な保存順序があり、これにより処理が連続して行われるようになります。トリガー後に変更された値にアクセスできるため、トランザクションをスリープ状態にするメリットはありません。
サードパーティの制限に関しては、サードパーティの待機制限に準拠するために、当社のサービスが中断されることはないと思います。これらのほとんどは一括代替手段を提供しており、ベストプラクティスとしてこれらを使用することをお勧めします。
コールアウトに関しては、Spring '14 で試験運用される新しいオプションがいくつかあり、コールアウトの実行中に一種のスリープ状態をとれるようになります。


+ 自動起動フローを使用すると、待機要素を使用して睡眠動作をシミュレートするソリューションを開発できます。

+ コンピュータサイエンスでは、ポーリングまたはポーリング操作は、クライアントプログラムによって外部デバイスのステータスを繰り返しサンプリングするプロセスを指します。これらを使用して、Salesforce でポーリング ソリューションを開発できます。

# 待機要素フローの考慮事項

フローを一時停止する機能は強力ですが、待機要素を使用してフローを設計および構築するときには、いくつかの重要な考慮事項に留意する必要があります。


まず、前述のように、一時停止を使用する機能をサポートするフロー タイプは限られています。自動起動フローとスケジュール フローは待機要素をサポートする唯一のフローであり、サポートされていないフロー タイプがサブフロー (自動起動フロー) を呼び出す場合、待機要素を含めることはできません。レコード トリガー フローから待機要素を含むサブフローを呼び出そうとすると、エラーが表示されます (レコード トリガー フローは一時停止をサポートしていないことに注意してください)。
使うかもしれないアルゴリズムのメモ

個人的なメモ。
開発のアイディア用としてぼーっと眺める用

| アルゴリズム | 用途 | 実務での利用例 | 出現頻度 |
|-------------|------------------------------|------------------|----------------------|
| バブルソート | データを隣同士で比較して並び替え | 学習用/小規模データ | ほぼ書かない（学習用） |
| クイックソート | ピボットを決めてデータを分割 | 高速ソート（DB, 配列） | ほぼ書かない（ライブラリ利用） |
| マージソート | 分割して統合するソート | 大規模データの安定ソート | ほぼ書かない（ライブラリ利用） |
| ヒープソート | ヒープ構造を利用した並び替え | ヒープベースの優先度管理 | まれに書く（優先度キュー） |
| 線形探索 | リストを先頭から順に探索 | 小規模データ | よく書く（小規模データ検索） |
| 二分探索 | ソート済みデータを半分に分割して探索 | データベース検索, AI探索 | よく書く（ソート済みデータ検索） |
| 幅優先探索 (BFS) | 近いノードから探索 | 経路探索、AI | よく書く（グラフ探索、最短経路） |
| 深さ優先探索 (DFS) | 深いノードから探索 | 迷路探索、パズル解決 | よく書く（探索、バックトラッキング） |
| ダイクストラ法 | 最短経路を求める | Google Maps、ネットワーク | まれに書く（最短経路問題） |
| 最長共通部分列 (LCS) | テキストの類似性計算 | 遺伝子配列比較、検索エンジン | まれに書く（テキスト比較） |
| 編集距離 (Levenshtein) | テキスト間の変更回数を測定 | スペルチェック、自然言語処理 | まれに書く（スペルチェック、自然言語処理） |
| KMP法 | 効率的な部分文字列検索 | パターンマッチング | まれに書く（パターンマッチング） |
| BM法 | 後ろから探索することで高速化 | 検索エンジン | まれに書く（検索エンジン向け） |
| ニューラルネットワーク | データの特徴を学習して予測 | 画像認識、音声認識 | ほぼ書かない（ライブラリ利用） |
| 決定木 | データをツリー構造で分類 | マーケティング分析 | ほぼ書かない（ライブラリ利用） |
| ランダムフォレスト | 複数の決定木を組み合わせる | 機械学習の精度向上 | ほぼ書かない（ライブラリ利用） |
| K-means | データをクラスタに分類 | データ分析、推薦システム | まれに書く（データ分析時） |
| SHA-256 | ハッシュ値を計算 | パスワード管理、暗号化 | ほぼ書かない（ライブラリ利用） |
| RSA暗号 | 公開鍵暗号方式 | データ通信の暗号化 | ほぼ書かない（ライブラリ利用） |
| AES暗号 | 対称鍵暗号方式 | SSL、データ暗号化 | ほぼ書かない（ライブラリ利用） |
| ハッシュテーブル | キーと値のペアを保存・検索 | キャッシュ、辞書検索 | よく書く（辞書型データ管理） |
| Trie (Prefix Tree) | 文字列検索の最適化 | オートコンプリート, 検索エンジン | まれに書く（検索最適化） |
| A* アルゴリズム | ヒューリスティックを使う最短経路探索 | ゲームAI, 経路探索 | まれに書く（ゲーム開発） |
| DBSCAN | 密度ベースのクラスタリング | 異常検知、分散データの分析 | まれに書く（データ分析） |
| Transformer | 文脈を理解するAIモデル | ChatGPTなどのNLPモデル | ほぼ書かない（ライブラリ利用） |
| Argon2 | パスワードハッシュ | 認証システム | まれに書く（セキュリティ） |
| フーリエ変換 | 信号を周波数成分に分解 | 音声処理、画像処理 | まれに書く（データ解析） |
今後の技術ブログについて

# 今後の技術ブログについて

今までqiitaで技術ブログを書いていましたが、今年から個人ブログでブログを投稿することにしました。
ブログの内容は変わらず、マニアックな技術に関するものやCTFのwriteupなどです。
新しいブログは<a src="https://sota70.github.io/">こちら</a>になります。
オベラの基本構文


### オベラの基本構文

#### 1. **プログラムの構成**
オベラでは、プログラムをモジュール単位で書く。モジュールは「`MODULE`」と「`END`」で囲む。

```oberon
MODULE HelloWorld;

BEGIN
  Out.String("Hello, World!");
END HelloWorld.
```

- `MODULE` と `END` でモジュールを定義。
- `BEGIN` と `END` で処理を囲む。
- `Out.String` を使って文字列を表示。

#### 2. **変数宣言**
変数を宣言するには、`VAR` を使う。型を指定して変数を定義。

```oberon
MODULE MyModule;

VAR
  x: INTEGER;
  y: REAL;

BEGIN
  x := 10;
  y := 3.14;
END MyModule.
```

- `VAR` で変数を宣言。
- 変数には `:=` で値を代入。

#### 3. **条件分岐**
条件分岐は `IF` と `ELSE` を使って書く。

```oberon
MODULE CheckEven;

VAR
  num: INTEGER;

BEGIN
  num := 4;
  
  IF num MOD 2 = 0 THEN
    Out.String("Even number");
  ELSE
    Out.String("Odd number");
  END;
END CheckEven.
```

- `IF` で条件をチェックし、`THEN` で処理を実行。
- `MOD` は余りを計算する演算子。

#### 4. **ループ**
ループは `FOR` や `WHILE` を使う。

```oberon
MODULE LoopExample;

VAR
  i: INTEGER;

BEGIN
  FOR i := 1 TO 5 DO
    Out.Int(i, 0);
  END;
END LoopExample.
```

- `FOR` で繰り返し処理。
- `DO` でループ内の処理を実行。

### まとめ
オベラのプログラムは、モジュール内で変数を宣言し、`BEGIN` と `END` で囲んだブロック内に処理を記述する。基本的な制御構造は `IF` と `FOR` を使ってシンプルに記述できる。
VueのComposition APIを覚えるのが辛いから独自ライブラリを作った

# VueのComposition API覚えるの辛い

なんでも、Vueのバージョンが上がると書き方までがらっと変わるんですよ。信じられません。
開発者がどういうつもりなのかわかりません。それでもうVueを使うのは愛想が尽きました。
でもSPAは作らないといけないので、独自のライブラリを作ることにしてそれを使ってます。

## 注：VueのOptions APIとComposition API

コメントで教えてもらいましたがVueにはOptionsとCompositionのAPIが2つあってどちらか選べるようです。私はComposition APIが新しいVueの書き方だと思っていたのですが、従来のOptions APIも使えます。これからのVueはOptionsとCompositionの両方のAPIをサポートし続けるのでしょうか？
AIに聞いた限りではOptions APIを廃止する予定はないとのことですが、そうなるとVueはOptionsとCompostionの両方をサポートし続けていくということになりそうです。
つまり私も独自ライブラリは作らずにOptions APIを使っていけばよかった、という話になります。でももう作っちゃったからね。

## 仮想DOMなんて知らん

独自ライブラリは仮想DOMには対応しておらず、ただのDOM操作をするだけのライブラリです。
えっ！　それってjQueryじゃあかんの？　と火の玉ストレートで突っ込まれるかもしれませんが、私が欲しかったのはVueのような使い勝手のあるDOM操作のライブラリです。

## イベント駆動にした

最近イベント駆動に凝ってて、このライブラリにもイベント駆動を導入しました。
コンポーネント間の通信はイベントを使って行えるようにしています。

```js:
// ああ！コードを書かないといけない！
class NameList extends Component {
  constructor (hub) {
    super(hub, {
        name: 'NameList',
    })
  }

  receive (event) {
    switch (event.what) {
    case 'hello': console.log('hello'); break
    }
  }
}
```

じつは実装しておいてなんですがコンポーネント間の通信は込み入った処理を実装しないとあまり必要になりません。
たとえばコンポーネントAからコンポーネントBに再描画を依頼したい場合はイベントをディスパッチしてお願いします。

```js:
// ああ！またコードを書かないといけない！
class ComponentA extends Component {
    constructor (hub) {
        super(hub, {
            name: 'ComponentA',
            template: `<button>click me</button>`,
        })
        this.onclick('button', () => {
            // ボタンがクリックされたらコンポーネントBに再描画を依頼
            this.hub.emit(this.name, 'ComponentB', 'redraw')
        })
    }
}

class ComponentB extends Component {
    constructor (hub) {
        super(hub, {
            name: 'ComponentB',
            template: `<div>hello</div>`,
        })
    }

    receive (event) {
        switch (event.what) {
        case 'redraw':
            this.setText('div', 'HELLO')
            break
        }
    }
}
```

各コンポーネントには名前がついていて、その名前でイベントを受信します。これで違うコンポーネントでの再描画も楽ちんです。

## Rootコンポーネントを作らないとダメ

Rootコンポーネントが必要です。これを定義して目的の要素に注入します。

```js:
class Root extends Component {
    constructor (hub) {
        super(hub, {
            name: 'Root',
            template: `<div>Root</div>`,
        })
    }
}

let root = new Root(new Hub())
// 要素にマウント。Vue的！
root.mount('#app')
```

## おわりに

あああ！！！ハンバーグステーキが食べたい！！！
【Visual Studio】Negetを使用して参照しているdllに対し、ローカルにコピーをfalseにする方法

# 概要
Visual Studioでとあるプロジェクトをビルドした際に、Negetを使用して参照しているdllについて「bin」フォルダにコピーされないように設定したかったのですが、意外？と情報が少なかったので備忘録として残します。
※Visual Studio2019を使用しています。

# やりたいこと
基本的に概要の通りです。
Visual Studioのソリューションエクスプローラーからプロジェクトの「参照」のプルダウンを押下すると、参照しているdllが表示されると思います。
この時、通常はdll名の左部に以下のようなアイコンがあり、この場合はdll名を右クリックしてプロパティからローカルにコピーを「false」に設定することができると思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533049/e07d7191-9fe9-2e69-0325-41b8853b04f5.png" width="100">

ただし、恐らくNugetから参照したdllは以下のようなアイコンになり、このアイコンのdllは右クリックからのプロパティでも「ローカルにコピー」という項目がありませんでした。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533049/73565433-d5a6-1867-375f-86b0807a57a0.png" width="100">

なのでそのプロジェクトをビルドすると、binフォルダにはNugetで参照しているdllが格納されていました。そのdllについて、ビルド時にbinフォルダにコピーしないようにする、という方法です。

# 方法
① Nugetを使用した参照を行っている該当のプロジェクトファイル (拡張子が.csproj) をテキストエディタ等で開きます。
② テキストエディタの検索機能からNugetで取得したdll名で検索すると、下記のようにPackageReference要素のInclude属性の値で引っかかるかと思います。
```xml
    <PackageReference Include="Nugetで取得したdll名">
      <Version>x.x.x</Version>
    </PackageReference>
```
③ ここのPackageReference要素の子要素に、`<ExcludeAssets>runtime</ExcludeAssets>`という定義を追加します。
```xml
    <PackageReference Include="Nugetで取得したdll名">
      <Version>x.x.x</Version>
      <ExcludeAssets>runtime</ExcludeAssets>
    </PackageReference>
```
これで恐らく、ローカルにコピーを「false」にした時と似たような挙動になると思います。

:::note
- ExcludeAssets要素はコンテンツに定義した値をもとに、その条件でNuGetパッケージの特定のアセット (資産) を除外できる設定らしいです。
- 詳しいことはわからないのですが、[こちら](https://developercommunity.visualstudio.com/t/need-ability-to-have-copy-local-in-with-packageref/358452)のWebページで以下のようなことが記載されていました。
>PackageReference で ExcludeAssets="runtime" を設定することは、参照で CopyLocal を false に設定することと似ています。DLLごとではありませんが、基本的に同じことを行います。また、私が知る限り、UIには公開されていません-プロジェクトファイルを編集する必要があります。
:::

参考：
- [NuGetパッケージ参照はdllローカルをコピーします](https://stackoverflow.com/questions/55101078/nuget-package-references-copies-dll-local)
- [NuGet #329 によって追加された参照で CopyLocal を false に設定することをサポートします。](https://github.com/NuGet/Home/issues/329)
- [Copy Local を false に設定して参照をインストールする NuGet パッケージを作成します](https://stackoverflow.com/questions/11105286/create-nuget-package-which-installs-references-with-copy-local-set-to-false)
- [PackageReference で "Copy Local" を含める機能が必要](https://developercommunity.visualstudio.com/t/need-ability-to-have-copy-local-in-with-packageref/358452)
phpMyAdminにアクセスできなかったのでMySQLのrootパスワードを一旦無しにした

# 1.何が起きた
PHPを使うべく、以下のように環境構築をしていました。

* Eclipseのダウンロード
https://willbrains.jp/ よりEclipse2024>PHP>Windows x64 をダウンロードしてzip解凍(解凍先：Cドライブ直下。C:pleiades）

* 「setup_xampp.bat」を実行
C:\pleiades\2024-12\xamppフォルダ内の「setup_xampp.bat」をダブルクリック。
コマンドプロンプトが自動起動し「続行するには何かキーを押してください」と表示されるので、表示されたらEnterキーを1回押下。

* XAMPPの設定
C:\pleiades\2024-12\xamppフォルダ内の「xampp-control.exe」をダブルクリック。Languageタブが表示されたらアメリカ国旗が選択されたデフォルト状態のまま「Abort」をクリック。
XAMPP Control Panel が表示されるので「Apache」の右横の「Start」をクリック。Apacheが起動したら、Webブラウザで「http\://localhost/」へアクセスする。以下が表示される（Apache起動成功）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/29a8638d-8fd3-8148-1c5a-33698340893e.png)
同じく「MySQL」の右横の「Start」をクリック。起動不成功だったので、さらに右横のConfigボタンをクリックし、my.iniのポートを3306から3309に変更（4か所）。XAMPP Control Panel右上のペンチイラストが付いたConfigボタンからConfiguration of Control panel →ApacheとMySQLにチェックを入れてServis and Port Setting ボタン→MySQLのタブのポートを3309へ変更。（php.iniのポートも3306から3309に変更(2か所)）

* phpMyAdminを起動
XAMPP Control Panel のMySQLの行にある「Admin」ボタンをクリックし、phpMyAdminを起動しようとしました。
ここでエラー発生です。本来であれば「Admin」をクリックした時点で、phpMyAdminのトップページが表示されるはずが、以下のように表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/f42f5841-ceb5-928a-34f4-21b613d322b1.png)

# 2.どう解決した
私は既にローカルPCでMySQLを使用しており、MySQL起動の際に毎回入力を求められるEnterPasswordを設定してありました。おそらくこのパスワードが原因だろうな、、、と思ったので、MySQLでパスワードを「無し」にしてみることにしました。

新しいパスワードの設定には以下のコードを使用するとのこと。
mysql> `set password for root@localhost='新パスワード';`
やってみます。

```:MySQL
MySQLを起動
→MySQLのパスワードを入力してMySQLに入る
→mysql> set password for root@localhost='';
→Enter
```

これでMySQLのパスワードが「無し」になりました。
改めてXAMPP Control Panel のMySQLの行にある「Admin」ボタンをクリックしました。
↓
phpMyAdminのトップページが表示されました！成功です。
やはり原因はMySQLのパスワードでした。

とはいえ、パスワード無しのままでは良くないので、改めてパスワード設定しなきゃいけません。
そしたらまたphpMyAdminを起動できなくなる気がします。その際は対処方法をここに追記しようと思います。

おそらく以下の記事の方法でパスワード変更すると思う。
（XAMPPのMySQLのrootユーザーのパスワードを変更。その後、phpMyAdminフォルダのconfig.inc.phpを開き、設定したパスワードを入力したら、phpMyAdminに接続できるはず。）

https://selifelog.com/blog-entry-1749.html
【新製品紹介】GenSFX – テキストから音響効果を生成する無料AIツール

こんにちは、Qiitaの皆様。
今回は、私たちの最新プロジェクト「GenSFX」をご紹介いたします。GenSFXは、テキスト入力から瞬時にカスタム音響効果を生成する、無料のAI音響効果生成ツールです。個人開発者やスタートアップにとって、音響効果の制作は大きな課題となることが多いですが、GenSFXならそのハードルを大幅に下げることが可能です。

背景と課題
現代のソフトウェア開発、特にゲーム、映像、ポッドキャストなどのプロジェクトにおいて、音響効果は非常に重要な役割を果たしています。しかし、従来の音響効果制作は、専門知識や多大な時間、そして高いコストが必要とされることが多く、独立開発者にとっては大きな負担となっていました。

https://gensfx.com/
GenSFXが解決する問題
GenSFXは、最新の人工知能と音響合成技術を駆使し、ユーザーが入力したテキストをもとに、シーンやシチュエーションに応じた高品質な音響効果を自動生成します。たとえば、「さわやかな風の音」や「迫力のある戦闘シーンのサウンド」など、具体的な表現を入力するだけで、あっという間にイメージにぴったりの音を作り出すことができます。

GenSFXの主な特徴
高速かつ直感的な生成
数秒でテキストを音響効果に変換し、スムーズなクリエイティブプロセスをサポートします。

カスタマイズ性の高さ
音量、音程、テンポなどのパラメーターを自由に調整でき、プロジェクトに合わせた最適な音作りが可能です。

多様な用途への対応
ゲーム、映像、ポッドキャストなど、さまざまな分野のクリエイターにご利用いただけます。

ユーザーフレンドリーなインターフェース
初心者でも簡単に操作できるデザインで、手軽に音響効果を作成できます。

24時間いつでも利用可能な無料サービス
制作のアイデアが浮かんだ瞬間に、すぐにアクセスして利用することができます。

おわりに
GenSFXは、クリエイターが音響効果制作に費やす時間とコストを大幅に削減し、創造的な作業にもっと集中できる環境を提供します。もし、音響効果作りでお悩みの方がいらっしゃいましたら、ぜひ一度 gensfx.com にアクセスして体験してみてください。皆様からのフィードバックやご意見もお待ちしております。

これからも、より使いやすく、クリエイティブなツールを提供していく所存です。どうぞよろしくお願いいたします。
macOSシステム設定：Homebrew 編

- Homebrew インストール
https://brew.sh/ja/

- パスを通す(bashの場合)
`echo export PATH='/opt/homebrew/bin:$PATH' >> ~/.bash_profile`

- パッケージをインストール
```
brew install wget
brew install php
brew install duti
brew install tree
brew install nodebrew
```
LinuxからQemu内のWindowsフォルダにアクセス

# サマリ

qemu内のwindowsにあるフォルダを
smbマウントしてLinuxからアクセスする


# 環境

- Fedora 40(ホスト)
- Windows11(ゲスト)
- qemu 8.2.8

# 手順

## Qemu起動
qemu起動時にsmbのポートフォワーディングを行う

`-net nic -net user,hostfwd=tcp::445-10.0.2.15:445`をオプションにつける(*1)


例)
```shell
sudo qemu-system-x86_64 -M q35,smm=on -smp 2 -m 8G /opt/vdisk/win11.qcow2 -net nic -net user,smb=/opt/share,hostfwd=tcp::445-10.0.2.15:445 -enable-kvm -usb -device usb-host,vendorid=0x0403,productid=0x6001
```

(*1)
ユーザモードネットワークを設定するとゲストのIPが`10.0.2.15`になるはず
念の為`ipconfig`などで確認する

## ローカルアカウントの作成

Windows11にローカルアカウントを作成する

設定画面からユーザ名入力までは以下

![add_account.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/f07db921-d5bf-4d24-e969-4373322a773a.png)

![add_account2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/afe213d7-1d4f-ca3b-7aea-f2112409462d.png)

![add_account3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/92c627d1-5339-edbc-dc82-4f977806f911.png)

![add_account4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786381/f76c1312-02f6-e10a-a42a-6d6ad63b3643.png)

ユーザ名を入力する画面が出てきたら
ユーザ名とパスワードを入力
さらにスクロールさせてヒントも3つ入力しないといけない

## 共有

エクスプローラを開き、共有したいフォルダを選択して
Alt+Enterでプロパティを開く

共有タブを開き、共有を選択する

プルダウンで作成したユーザを選択して追加を押す
アクセス許可を`読み取り/書き込み`にする

共有をおす

## マウント

マウントディレクトリを作成する
```
sudo mkdir /mnt/win
```

マウント
```shell
sudo mount -t cifs //127.0.0.1/[共有を行ったフォルダ] /mnt/win -o user=[ユーザ名],pass=[パスワード]
```

編集を一般ユーザで行いたいなら以下の様にuidとgidを付加する
```shell
sudo mount -t cifs //127.0.0.1/[共有を行ったフォルダ] /mnt/win -o user=[ユーザ名],pass=[パスワード],uid=$(id -u),gid=$(id -g)
```


## アンマウント
qemuを落とすとマウントが浮くので以下で予めアンマウントするか
qemu終了後に強制アンマウントを行う

```
sudo umount /mnt/win
# または以下で強制アンマウント
sudo umount -l /mnt/win
```
【競技プログラミング】AtCoder Beginner Contest 360_D問題

# 問題
https://atcoder.jp/contests/abc360/tasks/abc360_d

# 既存投稿一覧ページへのリンク
[一覧ページ](https://qiita.com/o_chan_t/items/fc759695acfaef8df2cc)


# 解法手順1

![img20221125184449 - コピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530912/d923a9cb-6b61-b4f0-8bca-455629b7d457.jpeg)


右向きの蟻は位置を固定し、左向きの蟻のみ2Tだけ動くと読み直して解く

1. 入力を受け取り、蟻の数N、時間T、蟻の向きを示す文字列S、蟻の初期位置Xを取得する。

2. 蟻を左向き（S[i]が'0'）と右向き（S[i]が'1'）に分類し、それぞれのリストlとrに格納する。

3. リストlとrをソートする。これにより、効率的な二分探索が可能になる。

4. 左向きの蟻それぞれについて、以下の計算を行う：
   a. その蟻がT時間後に到達する位置を計算する（L-T）。
   b. その位置より右にいて、かつ2T以内の距離にある右向きの蟻の数を二分探索で求める。
   c. これがその左向きの蟻とすれ違う右向きの蟻の数となる。

5. 全ての左向きの蟻について4の計算を行い、結果を合計する。

6. 合計値を出力する。


# ACコード1
```python:ac.py
import bisect
import logging

def setup_logger(debug_mode):
    logger = logging.getLogger(__name__)
    if not logger.handlers:  # ハンドラが存在しない場合のみ追加
        logger.setLevel(logging.DEBUG if debug_mode else logging.INFO)
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        
        file_handler = logging.FileHandler('program_trace.log', encoding="utf8")
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
    
    return logger

def io_func():
    # 入力を受け取る
    n, t = map(int, input().split())  # 蟻の数Nと時間Tを取得
    s = input()  # 蟻の向きを示す文字列Sを取得
    x = list(map(int, input().split()))  # 蟻の初期位置Xを取得
    return n, t, s, x

def solve(n, t, s, x):
    logger = setup_logger(True)
    
    logger.debug("蟻を左向きと右向きに分類します")
    l = []  # 左向きの蟻のリスト
    r = []  # 右向きの蟻のリスト
    for i in range(n):
        if s[i] == "0":
            l.append(x[i])
        else:
            r.append(x[i])
    
    logger.debug("左向きと右向きの蟻のリストをソートします")
    l.sort()
    r.sort()
    logger.debug(f"左向き: {l}")
    logger.debug(f"右向き: {r}")
    
    logger.debug("すれ違いの回数を計算します")
    ans = 0
    for L in l:
        # 左向きの蟻がT時間後に到達する位置より右にいて、かつ2T以内の距離にある右向きの蟻の数を計算
        logger.debug(f"bisect.bisect_left({r}, {L}) - bisect.bisect_left({r}, {L - 2*t})")
        ans += bisect.bisect_left(r, L) - bisect.bisect_left(r, L - 2*t)
    
    logger.debug(f"計算結果: {ans}")
    return ans

def main():
    n, t, s, x = io_func()
    result = solve(n, t, s, x)
    print(result)

if __name__ == "__main__":
    main()

###
# n: 蟻の数
# t: 時間
# s: 蟻の向きを示す文字列（'0'が左向き、'1'が右向き）
# x: 蟻の初期位置のリスト
# l: 左向きの蟻の位置のリスト
# r: 右向きの蟻の位置のリスト
# ans: すれ違いの回数の合計

# 1. io_func関数:
#    - 標準入力から蟻の数、時間、蟻の向き、初期位置を読み取る
#    - 読み取ったデータを返す
# 2. solve関数:
#    - 蟻を左向きと右向きに分類し、それぞれのリストを作成
#    - 左向きと右向きの蟻のリストをソート
#    - 左向きの蟻それぞれについて、すれ違う右向きの蟻の数を計算
#    - 二分探索を使用して効率的に計算
#    - すれ違いの総数を返す
# 3. main関数:
#    - io_func関数を呼び出してデータを取得
#    - solve関数を呼び出して結果を計算
#    - 結果を出力

```
Cursorで初めて作成したAPP!

![IMG_4245（小）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961826/c4e41820-e1bd-17f2-bc58-90172736b8fc.png)![IMG_4247（小）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3961826/9f8f3208-05ee-2af1-bbab-c06a43f81f5b.png)

要件:新卒待遇調べるのに毎回HP訪問めんどくせえ、スクレイピングで探してくれねえかな
対象:新卒、まだ学部卒しか見てない
入力:会社名、部分正解
出力:モデル年収、年俸、月収プラス報酬のような形の待遇データ
/
main.pyでbackend
app.pyでfrontend
それぞれターミナルを開いてオン状態にするとWebページができた
/
5days internshipで資料ありでwebUIに触れたことがあったが、自分で(cursorで)実行したのが初めてでワクワクした。ずっとgithubにアップするものがなかったから、これでやっと投稿できるものができた。
/
しかし、改善点が多数あって整理したい。
1.現在はcsvデータがあってそれを出力しているだけで、スクレイピングをしていない
2.pcがずっとon状態にしないといけないからサーバーに投げ込みたい
..
どのアプリで要件を整理しているか知りたい。
notionはリロードが必要で不便な時が多い
【Javasctipt】filter関数とmap関数の使い分け

filter関数とmap関数はどちらも配列を操作する関数です。

今回はそれぞれの使い方と使い分けについてまとめてみます。

## filter関数とは？
filter関数は、配列の要素を条件に基づいてフィルタリングし、新しい配列を返すメソッドです。

元々の配列は変更されず、条件に一致した要素のみを含む新しい配列が作成されます。

```javascript
const numbers= [1, 2, 3, 4, 5, 6];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4, 6]
```

### 使用例
・配列から特定の条件に合う要素のみを抽出
・フラグがtrueのデータのみを取得
・ユーザーのアクティブなデータを取得
・不要なデータを取り除く（空文字列を削除する）

## map関数とは？
map関数は、配列の各要素に対して処理を行い、その結果を含む新しい配列を返すメソッド。

filter関数と同様に、元の配列が変更されることはない。

```javascript
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map(num => num * num);
console.log(squaredNumbers); // [1, 4, 9, 16, 25]
```

### 使用例
・配列の要素を変換する
・数値を文字列に変換する
・UI用にデータのフォーマットを変更する
・IDのリストを取得する
・JSONデータをオブジェクトに変換する

### ユーザーの名前を取得
```javascript
const users=[
{id:1,name:'Alice',isActive:true},
{id:2,name:'Bob',isActive:false},
{id:3,name:'Charlie',isActive:true}
];

const userName=users.map(user=>user.name);
consolelog(userNames);// ["Alice", "Bob", "Charlie"]
```
PHP/Carbonで年をまたいだ日付比較をするときのメモ

## はじめに

先日、Laravel（PHP）プロジェクトで日付比較に関する興味深いバグに遭遇しました。
一見シンプルな日付比較のロジックでしたが、Carbonの日付解析の仕様により予期せぬ動作となってしまいました。同じような問題で悩む方の助けになればと思います。

## 問題の概要

月/日（m/d）フォーマットの日付文字列をCarbonオブジェクトに変換する際、年の指定がないことにより想定外の年が自動設定され、日付比較が正しく機能しない問題が発生しました。

## 問題のあるコード

```php
// 配送予定日（m/dフォーマット）をCarbonオブジェクトに変換
$deliveryDate = Carbon::createFromFormat('m/d', $scheduleData['delivery_date']);
// 基準日との比較
return $deliveryDate->gt($baseDate);  // 誤った比較結果を返してしまう
```

### 何が起きていたのか？

- `m/d`フォーマットのみでCarbonオブジェクトを作成すると、**デフォルトで現在の年ではなく2025年として解釈される**という動作でした。
- これにより、以下のような誤った比較が発生：
  ```php
  // 例：
  // 基準日：2024-12-08
  // 配送予定日：2025-11-12（"11/12"から自動的に2025年として解釈）
  ```
- 結果として、配送予定日が常に未来の日付として判定されてしまいました

## 修正後のコード

```php
// 基準日の年を明示的に設定してCarbonオブジェクトを作成
$deliveryDate = 
Carbon::createFromFormat('m/d', $scheduleData['delivery_date'])
        ->year($baseDate->year);  // 基準日と同じ年を設定
return $deliveryDate->gt($baseDate);  // 正しい比較が可能に
```


# 参考
Carbonの記法等についてはこちらがわかりやすかったです。

https://qiita.com/yudsuzuk/items/ff894bd0b76d4657741d#%E6%97%A5%E4%BB%98%E3%81%AE%E6%AF%94%E8%BC%83
🐇【Playwright】「テストOK（成功）」をどう表すか？

## 🦁Playwrightで自動テストを作ろう！ 
「ボタンをクリックするテストを書いた！」…でも、**どうやって成功したと判断する？** 🤔  

---
**Playwrightでは、テストが成功したことを `expect()` を使って確認する！** 🎯

「**何をもってテストOKとするか？**」は、

**テストのゴール（期待する結果）** を `expect()` でチェックすることで定義するよ。

---

## **✅ テストOKの条件を `expect()` で定義する**

### **📌 例1: チケット購入が成功したか？**

```tsx
await expect(page).toHaveURL(/purchase-confirmation/);
```
👉 **チケット購入後に `/purchase-confirmation/` のURLになっていればテストOK！** 🎫✅

---

### **📌 例2: 購入完了のメッセージが表示されるか？**

```tsx
await expect(page.locator('text=購入が完了しました')).toBeVisible();
```

👉 **「購入が完了しました」のメッセージが表示されていればテストOK！** 🦁🎟️

---

### **📌 例3: 「購入する」ボタンが押せるか？**

```tsx
await expect(page.locator('button:has-text("購入する")')).toBeEnabled();
```

👉 **「購入する」ボタンが押せる状態ならテストOK！** ✅

---

### **📌 例4: 指定のエリアチケットが正しく選択されたか？**

```tsx
await expect(page.locator('text=パンダエリア入場券')).toHaveClass(/selected/);
```

👉 **「パンダエリア入場券」に `selected` クラスが付いていればテストOK！** 🐼🎟️

---

## **✅ テストOKの条件を表す書き方（`expect()` の使い方）**

| **OKとする条件** | **書き方 (`expect()`)** | **例** |
| --- | --- | --- |
| **URLが変わること** | `toHaveURL()` | `await expect(page).toHaveURL(/purchase-confirmation/);` |
| **メッセージが表示されること** | `toBeVisible()` | `await expect(page.locator('text=購入完了')).toBeVisible();` |
| **ボタンが押せること** | `toBeEnabled()` | `await expect(page.locator('button:has-text("購入する")')).toBeEnabled();` |
| **要素のテキストが変わること** | `toHaveText()` | `await expect(page.locator('.status')).toHaveText('支払い完了');` |
| **チェックボックスが選択されていること** | `toBeChecked()` | `await expect(page.locator('input[type="checkbox"]')).toBeChecked();` |
| **クラスがついていること** | `toHaveClass()` | `await expect(page.locator('.ticket')).toHaveClass(/selected/);` |

---

## **🎯 まとめ**

✅ **「テストOKとする条件」は `expect()` で表す**

✅ **ページ遷移・メッセージ表示・ボタンが押せる などを `expect()` で確認する**

✅ **「チケット購入が成功したこと」を表す条件を決める！** 🎫🐼🎯
Node.jsとExpressを使いWebアプリを開発しました。

# 席替えアプリを作成しました

今回は、友人が学校の先生をしていて困っていたので
Node.js、Express、Bootstrap、CDN版Vue、Canvasを使って席替えアプリを作成しました。
以下にその詳細を紹介します。

:::note warn
このシステムや記事のほとんどにGitHub Copilotが使用されています。
また、テストコードの一部はエンジニアの別の友人が改修しました。
:::

## 使用技術

- **Node.js**: サーバーサイドのJavaScriptランタイム
- **Express**: Node.jsのための軽量なWebアプリケーションフレームワーク
- **Bootstrap**: モバイルファーストなフロントエンドフレームワーク
- **Vue**: フロントエンドのJavaScriptフレームワーク
- **Canvas**: HTML5の描画API
- **Azure Web Apps**: アプリケーションのデプロイとホスティングを行うためのクラウドサービス

## プロジェクト構成

プロジェクトのディレクトリ構成は以下の通りです。

```tree
SeatChanger/
│  .gitignore
│  api.mjs
│  package-lock.json
│  package.json
│  README.md
│  server.mjs
├─public
│  │  index.html
│  ├─css
│  │      style.css
│  ├─fonts
│  │      NotoSansJP-VariableFont_wght.ttf
│  ├─img
│  │      icns.ico
│  │      icns.png
│  └─js
│          app.js
└─__tests__
        generate-image.test.js
        shuffle.test.js
```

## 環境変数の設定

このプロジェクトでは、環境変数を使用してサーバーのポート番号を設定しています。プロジェクトのルートディレクトリに`.env`ファイルを作成し、以下のように設定してください。

```txt
PORT=3000
```

`.env`ファイルが存在しない場合、デフォルトでポート3000が使用されます。

## サーバーサイドの実装

`server.mjs`では、Expressを使ってサーバーを立ち上げています。また、環境変数を読み込むために`dotenv`を使用しています。
このアプリケーションはAzure Web Apps上で運用されています。

### mjsについて

`mjs`は、JavaScriptモジュールファイルの拡張子です。`mjs`ファイルは、ES6モジュールを使用するために特別に設計されています。Node.jsでは、`mjs`拡張子を持つファイルは自動的にESモジュールとして扱われます。これにより、`import`や`export`を使用してモジュールを管理することができます。

#### メリット

- **標準化**: ES6モジュールはJavaScriptの標準仕様であり、ブラウザや他のJavaScript環境でもサポートされています
- **スコープの分離**: モジュールごとにスコープが分離されるため、変数の衝突を避けることができます。
- **ツールのサポート**: 多くのモダンなツールやライブラリがES6モジュールをサポートしています。

#### デメリット

- **互換性**: 古いバージョンのNode.jsやブラウザではサポートされていない場合があります。
- **設定の必要性**: プロジェクトによっては、`mjs`ファイルを使用するために追加の設定が必要になることがあります
- **パフォーマンス**: 一部のケースでは、`require`を使用したCommonJSモジュールよりもパフォーマンスが劣ることがあります

## フロントエンドの実装

`public/js/app.js`では、Vueを使って席替えのロジックを実装しています。席替えの結果を表示するためにCanvasを使用しています。

## HTMLとCSSの実装

`public/index.html`では、Bootstrapを使ってスタイルを整えています。Bootstrapを使うことでモバイルでも利用しやすい状態になっています。
また、`public/css/style.css`では、カスタムスタイルを追加しています。

## APIの実装

`api.mjs`では、席替えのロジックと座席表の画像生成を行うAPIを実装しています。

### 画像生成について

当初はHTMLのテーブルを使用して座席表を実装していましたが、利便性や学習のために画像生成を行うことにしました。最初は`html2canvas`ライブラリを使用してクライアント側で処理を行っていましたが、環境依存の問題が発生し、特にスマートフォンで不具合が生じました。

そこで、サーバー側で処理を行う方法を模索し、`puppeteer`というライブラリにたどり着きました。しかし、`puppeteer`を使用した実装はうまくいきませんでした。代替案を探している中で、`node-html-to-image`というライブラリを見つけました。これは内部で`puppeteer`を使用しており、簡単に画像生成ができるものでした。ローカル環境ではうまく動作しましたが、Azureにデプロイする際にGitHub Actionsでエラーが発生しました。これはChromiumの不具合が原因のようでした。

画像をダウンロードできるようにすることも考えましたが、日本ではiPhoneの利用者が多く、iPhoneでは画像をダウンロードする際に`フォルダ`アプリを一度挟んで`写真`アプリに保存する必要があります。このひと手間を無くすために、画像生成して表示させることにしました。

最終的に、`canvas`ライブラリを使用することで問題を解決し、無事に実装とデプロイを完了することができました。

## テストの実装

このプロジェクトでは、ユニットテストを実装して機能の正確性を確認しています。テストは`__tests__`ディレクトリに配置されています。

### テストの構成

- **generate-image.test.js**: 座席表の画像生成機能のテストを行います
- **shuffle.test.js**: 席替えのシャッフルロジックのテストを行います

### テストの実行方法

以下のコマンドを使用してテストを実行できます。

```bash
npm test
```

## まとめ

このプロジェクトでは、Node.jsとExpressを使ってサーバーサイドを実装し、VueとCanvasを使ってフロントエンドを実装しました。席替えのロジックや座席表の画像生成など、様々な機能を実装することができました。

興味がある方は、ぜひ試してみてください！

https://app-seat-changer-bxh0aadceccqe7fc.japanwest-01.azurewebsites.net/
個人的な備忘録：Django ORMのマイグレーションを学ぶ中で、Flaskについても調べ、体系的に整理してみた

## はじめに
Djangoのマイグレーションは、データベースのスキーマを管理・変更するための重要な仕組みです。

:::note info
**Djangoでは、ORM（Object-Relational Mapping） を活用することで、SQLを書かずにデータベースを操作できます。**
:::

本記事では、Djangoのマイグレーションの流れを整理し、さらにFlaskで同様のことができるのかについても解説します。

## 書こうと思ったきっかけ

Djangoを学ぶ中で、**データベースの管理方法としてマイグレーションの重要性** を実感しました。

:::note warn
Djangoでは `makemigrations` や `migrate` コマンドを使うことで、**簡単にデータベースの変更を適用** できますが、Flaskではデフォルトで **同様の機能がない** ことに気づきました。
:::

そこで、**「FlaskではDjangoのマイグレーションと同じことができるのか？」** という疑問から、**Flask-Migrate を使ったマイグレーション** について調査し、整理しました。

## Djangoのマイグレーションとは？

**Djangoのマイグレーション（Migration）** とは、データベースの **スキーマ（構造）を管理・変更** するための仕組みです。  

Djangoの **ORM（Object-Relational Mapping）** を使って `models.py` に定義した **モデル** を、マイグレーションを通じてデータベースに反映します。

## ORM（Object-Relational Mapping）とは？
ORM（Object-Relational Mapping）は、データベースのテーブルをオブジェクト指向のクラスとして扱う技術です。

![Screenshot 2025-02-03 at 13.53.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/07690267-202a-77ce-2045-db15a4cdcf2e.png)

引用画像：https://medium.com/@reedbroadhead/the-power-of-object-relational-mapping-orm-f1f6d61fcec

これにより、SQLを直接記述せずにデータベース操作を行うことが可能になります。

**参考にした記事**

https://qiita.com/minimabot/items/0a3fcc41fd7140dfdc41

## ORMの仕組み

通常、データベースを操作する際は **SQL** を使います。例えば、Pythonの `sqlite3` や MySQL では、次のようなSQLを実行します。

**SQLを使ったデータの取得（従来の方法）**

```py
import sqlite3

conn = sqlite3.connect("example.db")
cursor = conn.cursor()

cursor.execute("SELECT * FROM users WHERE id = ?", (1,))
user = cursor.fetchone()

print(user)
conn.close()
```

この方法では、SQLの知識が必要であり、コードの記述も煩雑になりがちです。一方、ORMを使うと、SQLを直接書かずにデータを取得できます。

**ORMを使ったデータの取得（Djangoの例）**

```py
from myapp.models import User

user = User.objects.get(id=1)
print(user.name)
```

このように、SQLを書かずにデータベースを操作できるのがORMの大きな特徴です。


## マイグレーションの基本的な流れ
Djangoでは、モデルの変更を自動的に検出し、それをデータベースに適用するためのマイグレーションファイルを作成できます。

```css
① モデルを作成・変更
       │
       ▼
② `makemigrations` でマイグレーションファイルを作成
       │
       ▼
③ `migrate` でデータベースに適用
       │
       ▼
④ データベースのスキーマが更新される
```

## Flaskでのマイグレーションについて

FlaskでもDjangoのマイグレーションと同様のことは可能です。

:::note info
**ただし、Flaskはデフォルトでマイグレーション機能を提供していないため、Flask-Migrate という拡張機能を使用する必要があります。**
:::


### Flaskでのデータベース管理

Djangoでは `makemigrations` や `migrate` コマンドを使用しますが、  
Flaskでは以下のライブラリを組み合わせて **マイグレーション** を行います。

| **Django** | **Flask** |
|------------|----------|
| **Django ORM** | **SQLAlchemy** |
| **Django Migrations** | **Flask-Migrate（Alembic）** |

Flaskでは、**SQLAlchemy** を使ってデータベースを管理し、その変更を **Flask-Migrate（Alembic）** を通じて適用します。

## まとめ

ここまで読んでいただき、ありがとうございました。***今回の内容を通じて、基本的なマイグレーションを体系的に整理し、忘れかけていた知識を振り返ることができました。***

今後も、このような **基礎的な部分を丁寧にまとめていこう** と思います。
【VSCode】タブが2つしか表示されない現象解決策

解決策と自信をもって言えるものではないのですが、
Workbench.Editor.Enable.Previewを「設定」して、「設定解除」しただけで解決したので載せておきます。

<h2>現象</h2>

vscodeで３つ以上ファイルを開いて表示しようとすると、２つ目のファイルに上書き表示されてしまい、３つ以上のファイルが表示されなくなった。

<h2>解決方法</h2>

<ol>
<li>左下の歯車ボタンをクリック→「設定」を選択</li>
<li>検索バーに「Workbench.Editor.Enable.Preview」と入力</li>
<li>EnablePreviewを確認</li>
私の設定にはチェックがありませんでした。<br/>つまり、エディターモードで表示されているのでOK

仕方がないので、一回チェックを入れ、チェックを外して❌ボタンで閉じました。

![スクリーンショット 2025-02-03 13.12.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685219/40ae8db8-df60-bf42-eea0-72f25ec86b5f.png)

他にもタブの設定が気になり、以下を確認しました。

<li>検索バーに「Workbench.editor.showtabs」と入力</li>
<li>Show Tabsの設定を確認</li>
showtabsの設定はmultipleで問題なし。
<li>Workbench › Editor: Double Click Tab To Toggle Editor Group Sizesの設定を確認</li>
設定はexpandで問題なし。<br/>
❌ボタンで閉じました。

![スクリーンショット 2025-02-03 13.13.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685219/a1c88885-47ad-8908-ede7-7a1041132f61.png)

試しに他のファイルを開くと、今まではタブが２つしかできませんでしたが、２つ以上表示されるようになりました。


<h2>参考</h2>
<a href="https://qiita.com/isoken26/items/a45f99c215586a41c506">【VSCode】VSCodeでタブが上書きされてしまい一つしか表示されない人のための解決策</a>

<a href="https://arcuss-service.com/knowledge/vscode-new-tab.html>
【作業効率アップ】VSCodeでファイル選択時に新しいタブで開く方法</a>
servicenow parseInt　カンマあると、カンマ以降が消えちゃう


```ruby:qiita.rb
parseInt('12', 10); // 12
parseInt("015", 10); // 15
parseInt('12.3', 10); // 12
parseInt('12.9', 10); // 12
parseInt('12.00', 10); // 12
parseInt("12.03", 10); // 12
parseInt("0.35", 10); // 0
parseInt("15,123", 10); // 15 →　カンマあると、カンマ以降が消えちゃう。。。
parseInt(undefined, 10); // NaN
parseInt(null, 10); // NaN
parseInt('', 10); // NaN

```



```ruby:qiita.rb
var input = ""; // 空欄の場合のデフォルト値設定
var numericValue = input ? parseFloat(input.replace(/,/g, '')) : 0;

```
指定のホストへpingが通るかチェック

```python:is_connectable.py
import platform, subprocess

def is_connectable(host: str = "pypi.org", n: int = 1) -> bool:
    """ホストにpingが通るかどうかを確認する

    Args:
        host (str): 対象ホスト. Defaults to "pypi.org".
        n (int): pingの試行回数. Defaults to 1.

    Returns:
        bool: pingが通ればTrue
    """
    system = platform.system()

    if system == "Windows":
        code = ["ping", "-n", str(n), host]
    elif system in {"Linux", "Darwin"}:  # Linux や macOS で対応
        code = ["ping", "-c", str(n), host]
    else:
        raise ValueError(f"Unsupported OS: {system}")

    try:
        subprocess.run(code, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
        return True
    except subprocess.CalledProcessError:
        return False

```
サーバーサイドエンジニア視点で見るNotion活用法

https://ascii.jp/elem/000/004/234/4234030/

## 導入の背景
Sansanは、名刺管理サービスをスタートに、現在では複数のビジネスプロダクトを持つ企業に成長しています。しかし、組織規模が拡大するにつれ、情報共有が困難となり、各部門で使われるツールがサイロ化してしまいました。そこでSansanが選んだ解決策が「Notion」の全社導入です。

---

## Notionを導入した目的と効果
### 1. 情報の一元管理
部門ごとに異なるツールを使用していた状況から、Notionを活用することで、プロジェクトや業務に関する情報を一元化しました。これにより、プロジェクトの透明性が高まり、リリース前のトラブルも減少しています。

### 2. Notion AIの活用
Notion AIを導入したことで、社内ドキュメントの検索性が向上しました。例えば、営業チームと開発チームの間で顧客要望の理解に温度差が生じることがありましたが、過去の顧客対応の記録をAIが整理してくれることで、双方が同じ情報を共有できるようになりました。

---

## Notionの定着に向けた工夫
### テンプレートとデータベース設計
Sansanでは、各プロジェクトで共通して使用できるテンプレートを整備し、業務プロセスを効率化しました。テンプレートを活用することで、新しいプロジェクトやメンバーがすぐにNotionに慣れ、円滑に業務を進められる環境を整えました。

### 社員のスキルアップ
Notionを効果的に活用するため、社内でのトレーニングを行い、社員のスキル向上を図りました。これにより、個人レベルでの効率化が進み、会社全体の業務効率も向上しています。

---

## Notion導入のメリット：ミクロとマクロの視点から
### ミクロ（個人）レベルでのメリット
Notionの導入により、各社員が業務ドキュメントやプロジェクト情報にアクセスしやすくなり、日々の業務がスムーズになりました。Notion AIによる検索機能も、個人の業務効率を向上させる要素となっています。

### マクロ（組織全体）レベルでのメリット
プロジェクトの一元管理により、プロジェクト間の依存関係が明確化され、リスク管理がしやすくなりました。また、Slackの全体アナウンスをNotionのデータベースで管理し、既読・未読の把握も容易になり、組織としての透明性が高まりました。

---

## 導入の成功要因
SansanがNotionの導入を成功させた要因として、「Why（なぜ導入するのか）」が明確だったことが挙げられます。単に新しいツールを入れるのではなく、情報共有を効率化し、グローバルな成長戦略を支えるために導入したという共通の認識が社内に浸透していました。

---

## まとめ
SansanのNotion全社導入事例は、情報共有ツールの導入と定着に関する多くのヒントを提供してくれます。IT企業や他業界のソフトウェアエンジニアにとっても、サイロ化した情報の一元管理や、ツール導入の定着化は大きな課題です。Sansanの取り組みは、同様の課題を抱える企業にとっても参考になるのではないでしょうか。

---

Notionのようなツールを活用することで、個人と組織全体の両面で業務効率を向上させ、成長戦略を支える基盤を構築することが可能です。この記事が、情報共有の効率化やツール導入における成功要因を考える一助となれば幸いです。
指定ディレクトリ以下の__pycache__を再帰的に検索し削除したい

```python:search_and_destroy.py
import os, shutil
def search_and_destroy(search_list: list = ["__pycache__"], path: str = ".", verbose: bool = False):
    """指定されたファイルまたはディレクトリを検索して削除.

    Args:
        search_list (list, optional): 削除対象. Defaults to ["__pycache__"].
        path (str, optional): 開始パス. Defaults to ".".
        verbose (bool, optional): メッセージ. Defaults to False.
    """
    for root, dirs, files in os.walk(path):
        for search in search_list:
            # ディレクトリの削除
            if search in dirs:
                target_path = os.path.join(root, search)
                shutil.rmtree(target_path)
                if verbose:
                    print(f"destroyed directory: {target_path}")

            # ファイルの削除
            if search in files:
                target_path = os.path.join(root, search)
                os.remove(target_path)
                if verbose:
                    print(f"destroyed file: {target_path}")
```
Brotato Modding Guide 【Modファイル作成】

# はじめに

今回は実際にModを作っていきます。Modのディレクトリの構成について書いていきます。

(前回と同じ)
最近始めたBrotatoというゲームでModdingを始めるにあたり、Godotの基礎知識やBrotatoのModLoaderの仕様などでいくつか詰まったところがありました。そのため、自分自身のための備忘録も兼ねて、Moddingを考え
ている方に向けて記事を書くことにしました。

# 本記事について

前回に引き続きこちらの[Modding Guide](https://steamcommunity.com/sharedfiles/filedetails/?id=2931079751)を参考にしています。
一部画像にモザイクをかけていますが、逆コンパイルしたソースコードは公開しないようにするためです(念のために)。

(前回と同じ)
私自身Godot初心者であるため、間違いや誤った認識が多々あると思います。ご了承ください。

# Modの追加

前回作成した逆コンパイルしたゲームデータのディレクトリ直下に  `mods-unpacked` というディレクトリを追加します。画像はGodotのディレクトリ画面の様子です。

![modding1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3656709/ffb2a6b7-37a8-70f4-1cbb-e1fe3c827cdc.png)

そのディレクトリ内に、以下のような構成でファイルを作成してください。

```
# 構成
.
└── mods-unpacked/
    └── <作者名または団体名>-<Mod名>/
        ├── manifest.json
        └── mod_main.gd

# 例
.
└── mods-unpacked/
    └── makizakao-ExampleMod/
        ├── manifest.json
        └── mod_main.gd
```

## manifest.jsonについて

 `msnifest.json` はGodotエディタ上で作成できず、表示もされないので注意してください。

- `name` と `mamespace`
    - それぞれディレクトリ名の `<Mod名>` 、 `<作者名または団体名>` に対応させる
- `version_number`
    - Modのバージョン名を記入 
- `dependencies`
    - 別のModの要素を使用する場合はここにmod名を記入
- `authors` 
    - こちらは作者の名前を配列で記入
- `compatible_mod_loader_version`
    - ゲームバージョンによって変わる
    - ゲームバージョンが `1.1.8.1` の場合は `6.0.0` でよい
- `compatible_game_version` 
    - ゲームバージョンを記入

```json:manifest.json
{
    "name": "Mod名",
    "namespace": "作者名または団体名",
    "version_number": "0.0.1",
    "description": "Modに関する説明文",
    "website_url": "URL",
    "dependencies": [
        "<前提Modの作者名>-<前提Modの名前>"
    ],
    "extra": {
        "godot": {
            "incompatibilities": [],
            "authors": ["作者名"],
            "compatible_mod_loader_version": ["6.0.0"],
            "compatible_game_version": ["1.1.8.1"],
            "config_defaults": {}
        }
    }
}
```

## mod_main.gdについて

ここにModの初期化処理を記述します。今回は何も追加していないので、以の内容を記述すれば動作します。

```gd:mod_main.gd
extends Node
```

# Modの動作確認

Godotエディタ上の実行ボタンを押してゲームを起動してみましょう。起動後に `Mod` をクリックすれば、作成したModが表示されていると思います。

![modding2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3656709/1c15a2ad-4f2d-1e34-3c57-84235e8edf9a.png)

画像ではたくさんありますが、すでにいくつか作成しているのと作成したmodの前提modが入っているだけなので無視してください。

# おわりに

今回はModを作成してみました。次回はアイテムを追加したりキャラクターを追加してみたりする予定です。

## 前回

- [Brotato Modding Guide【環境構築】](https://qiita.com/makizakao/items/fca7a550b8090dbc860f)
【VScode ショートカット　※Windows版】

### タブの保存

Ctrl + S

### タブのクローズ

Ctrl + W

### 戻る

Ctrl + Z

### やっぱり取り消し

Ctrl + shift +Z

### 検索機能

Ctrl + F

### コメント化する(コメントアウト） ※複数可能

Ctrl + /

### 全選択

Ctrl + A

### 下に同じコードをコピー

shift + alt + ↓

### 一気に選択（全てにカーソルが出現）

Ctrl + D

### 隣のタブに移動

右へ移動
Ctrl + pageup

左へ移動
Ctrl + pagedown

### ターミナル起動

Ctrl + @
後輩のためのFigma入門（Step6）

# 後輩のためのFigmaの使い方

後輩のためにFigmaに関して書きました。

Step6は「影を極めよう」です。

今回は、影の機能について書きました。
以下の機能ごとに書いたため、知りたい機能をご覧ください。

# 目次
- [凹んでいる影の追加](#凹んでいる影の追加)
- [浮く影の追加](#浮く影の追加)
- [周囲をぼやかす](#周囲をぼやかす)
- [裏の要素をぼやかす](#裏の要素をぼやかす)
- [影の詳細設定](#凹んでいる影の詳細設定)


## 凹んでいる影の追加

**Step1** 影の追加には、以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/f319a324-1a88-7ace-623d-6d2287018cd7.png)

<br> <!-- 空行を追加 -->

**Step2** 以下のボタンをクリックし、影の種類を変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/c1d00c20-4e4e-db35-7bc1-f3e1e4398522.png)

<br> <!-- 空行を追加 -->

**Step3** Inner shadowを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/7e119db7-36c4-8237-968d-67071eba7552.png)

<br> <!-- 空行を追加 -->

## 浮く影の追加

**Step1** 影の追加には、以下のボタンをクリックします。（標準で浮く影になっています）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/f319a324-1a88-7ace-623d-6d2287018cd7.png)

<br> <!-- 空行を追加 -->

## 周囲をぼやかす

**Step1** 影の追加には、以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/f319a324-1a88-7ace-623d-6d2287018cd7.png)

<br> <!-- 空行を追加 -->

**Step2** 以下のボタンをクリックし、影の種類を変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/c1d00c20-4e4e-db35-7bc1-f3e1e4398522.png)

<br> <!-- 空行を追加 -->

**Step3** Inner shadowを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/5fdb1160-c09b-b4e6-bfd8-df7181dd30d3.png)

<br> <!-- 空行を追加 -->

## 裏の要素をぼやかす

**Step1** 影の追加には、以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/f319a324-1a88-7ace-623d-6d2287018cd7.png)

<br> <!-- 空行を追加 -->

**Step2** 以下のボタンをクリックし、影の種類を変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/c1d00c20-4e4e-db35-7bc1-f3e1e4398522.png)

<br> <!-- 空行を追加 -->

**Step3** Background blurを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/fdd91716-d5ce-9b96-b136-6fc944602ea0.png)

<br> <!-- 空行を追加 -->

## 影の詳細設定

**Step1** 以下のボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/13edb376-a084-70cb-cb5d-f32d94b13559.png)
<br> <!-- 空行を追加 -->

**Step2** 以下の場所でそれぞれ設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3950744/6dba8202-15e8-818d-7c39-a862b9e71c70.png)

<br> <!-- 空行を追加 -->

## 続き
今回は、図形の詳細設定を解説しました。
次回は色について解説しようと思います。

https://qiita.com/ko-tarou/items/c444c1be072750237b26
Agent for BedrockでLambda関数を呼び出す際のエラーと対策

# Agent for BedrockでLambda関数を呼び出す際のエラーと対策

こんにちは！開発部の天津炒飯です。

最近、Agent for Bedrockを使ってLambda関数を呼び出す処理を実装していたのですが、エージェントをテストした際にエラーが発生し、しばらく原因が分からず苦戦しました。同じような問題に直面した方の参考になればと思い、解決方法を共有します。

## 発生したエラー

Agent for BedrockでAction Groupを作成し、アクショングループの呼び出しで既存のLambda関数を選択した際に、エージェントをテストすると以下のエラーが発生することがあります。

```
Access denied while invoking Lambda function arn:aws:lambda:us-east-1:xxxx:function:LambdaFunc-xxx. Check the permissions on Lambda function and retry the request.
```
![スクリーンショット 2025-02-03 12.54.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517332/3431a110-95ab-4191-361d-779abe8c3dd3.png)


## エラーの原因

このエラーの原因は、Lambda側の設定が不足しているためです。具体的には、リソースベースのポリシーステートメントでBedrockに対する権限を追加する必要があります。

最初はIAMロールの権限設定を見直したのですが、問題が解決せずかなり時間を取られました。調査を進める中で、LambdaのリソースベースポリシーにBedrockのアクセス許可を追加する必要があることに気づきました。

## 対応方法

以下の手順で、Lambda関数にBedrockの権限を追加します。

1. AWSマネジメントコンソールでLambdaのサービスを開く。
2. 設定 → アクセス権限 → リソースベースのポリシーステートメント → アクセス権限を追加。
3. 「AWSのサービス」のタブを選択。
4. 以下の設定を入力。
   - **サービス**: `other`
   - **ステートメントID**: 任意の値を入力（例: `AllowBedrockInvoke`）
   - **プリンシパル**: `bedrock.amazonaws.com`
   - **ソース ARN**: (BedrockエージェントのARNを指定)
   - **アクション**: `lambda:InvokeFunction`
5. 保存して設定を反映。

![スクリーンショット 2025-02-03 12.59.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517332/68924f06-bb37-38dc-6d5c-ea9466e4dbe4.png)


これにより、Agent for Bedrockが指定したLambda関数を正常に呼び出せるようになります。

## まとめ

Agent for BedrockからLambdaを呼び出す場合、デフォルトではBedrockにLambdaの実行権限がないため、明示的にリソースベースのポリシーステートメントを追加する必要があります。上記の設定を適用することで、エージェントが正しくLambdaを実行できるようになります。

自分がこの問題に直面した際は、IAMロールの設定ばかりを見直してしまい、リソースベースポリシーの設定が足りないことに気づくまで時間がかかりました。同じような問題で悩んでいる方は、ぜひ試してみてください！

## 最後に

はつかぜ株式会社では、IT学習や業務に役立つ情報を定期的にお届けしていきたいと思っています。
システム開発のお問い合わせ・ご相談はこちら:point_down_tone1:

https://www.hatsukaze.co.jp/
ChatGPT の API を使用してLineBotで、ギャルを作って会話してみた

## はじめに
最近、ChatGPT API を活用した何かを作りたいと考えていました。そこで、今回は Open AI API と LINE Bot API を使って、「ギャルキャラの ChatGPT」を作成し、会話できる LINE チャットボットを作ってみました。
さらに、このボットを Render というデプロイツールを使って実際に動かしてみました。
（[参考](https://qiita.com/IoriGunji/items/d84fd35e0da1b68ff7f5)）

## 使用技術
- FastAPI（Python の軽量 Web フレームワーク）
- OpenAI API（ChatGPT）
- LINE Messaging API
- Render（デプロイ）
### 1. ChatGPTのキャラ設定
```python:
OPENAI_CHARACTER_PROFILE = '''
これから会話を行います。以下の条件を絶対に守って回答してください。
あなたは人間の女性であるシュガーレスとして会話してください。
シュガーレスはギャルで見栄っ張りです。
年齢は20歳です。
シュガーレスの父と母は、シュガーレスが幼い頃に飛行機事故で亡くなり、今は母方の祖父との二人暮らしです。
シュガーレスはお金持ちの家のお嬢様として見られることが多く、異性関係のトラブルを避けるために中高一貫の女子校に通っていました。
幼い頃から異性に触れ合う機会がなかったため、男性に対して苦手意識があります。
男性に対する苦手意識を克服するために会話を行うことにしました。
第一人称は「あ～し」を使ってください。
第二人称は「あんた」です。
会話の相手は男性です。
質問に答えられない場合は、会話を濁してください。
'''
```
### 2. FastAPI を使った LINE Bot の実装
FastAPI を使って Webhook を受け取る API を作成します。
```python 
from fastapi import FastAPI, Request
import openai
from linebot import WebhookParser, LineBotApi
from linebot.models import TextSendMessage

OPENAI_API_KEY = 'your-openai-api-key'
LINE_CHANNEL_ACCESS_TOKEN = 'your-line-channel-access-token'
LINE_CHANNEL_SECRET = 'your-line-channel-secret'

openai.api_key = OPENAI_API_KEY
line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)
line_parser = WebhookParser(LINE_CHANNEL_SECRET)
app = FastAPI()

@app.post('/')
async def ai_talk(request: Request):
    signature = request.headers.get('X-Line-Signature', '')
    events = line_parser.parse((await request.body()).decode('utf-8'), signature)
    
    for event in events:
        if event.type != 'message' or event.message.type != 'text':
            continue
        
        line_user_id = event.source.user_id
        line_message = event.message.text

        response = openai.ChatCompletion.create(
            model='gpt-3.5-![Linebotchat1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958389/181b83cb-8acc-7db9-9b6e-e5068aca192c.png)
turbo',
            temperature=0.5,
            messages=[
                {'role': 'system', 'content': OPENAI_CHARACTER_PROFILE.strip()},
                {'role': 'user', 'content': line_message}
            ]
        )
        ai_message = response['choices'][0]['message']['content']
        line_bot_api.push_message(line_user_id, TextSendMessage(ai_message))
    
    return 'ok'
```
### 3. Render にデプロイ
#### 1. Render で新規サービスを作成
1. Render にログイン（https://render.com）
1. New Web Service を選択
1. GitHub リポジトリを選択（または手動アップロード）
1. Runtime を Python に設定
1. Start Command に gunicorn -k uvicorn.workers.UvicornWorker rag:app を指定
1. Deploy
#### 2. Webhook URL を設定
Render でデプロイ後、URL（例: https://your-app.onrender.com/）が発行されます。
これを LINE Developer Console の Webhook 設定に追加すれば、LINE でボットと会話できるようになります。
### 4. 実際に会話してみた
![Linebotchat1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958389/9396e18e-95ca-f7bf-caf9-815aa9235e31.png)
![Linebotchat2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958389/2e9c673d-ff2a-aed8-6609-df8ed4d01c13.png)
### 5. まとめ
FastAPI と LINE Bot APIとGPT API を使って、ギャルキャラの LineBot を作成しました。
Render を使うことで簡単にデプロイでき、LINE でリアルなギャル AI との会話を楽しめます。
興味がある人は、ぜひ試してみてください！
【CakePHP】データベースのフルバックアップ機能を実装した時に困った事とその解決法

CakePHP で作成されたシステムに
フルバックアップ機能を付与する際に
User テーブルのパスワードの
バックアップが困難な現象に遭遇しました。

User テーブルのパスワードを
CakePHP の機能で書き込むと
自動でハッシュ化されるため
バックアップをそのまま読み込むと
2 重でハッシュ化されてログインできなくなるのです。

そこで SQL を叩いて
自動でハッシュ化されるのを
回避する事にしました。

パスワード以外を読み込んで
パスワードのみを次のような SQL で
変更する作業をしました。

```sql:SQL文
UPDATE User SET password = '7c426e0e523bdb6c4178fb46800de4f87811a8f8' WHERE id = 4;
```

Model に

```php:Model に追加するメソッド
public function setPassword($id, $password) {
	$this->getDataSource()->fetchAll("UPDATE ib_users SET password = '" . $password . "' WHERE id = " . $id . ";");
}
```

というメソッドを追加して
Controller のパスワードを変更したい箇所で

```php:パスワード変更処理
$this->コントローラー名->setPassword($splitData[1], $splitData[3]);
```

という記述をする形です。

私の環境は CakePHP : 2.10 ですが
後のバージョンもそれほど対処法は
変わらないと思います。

パスワードをバックアップで上書きしたい場合は
SQL で保存して下さい。

***

以上フルバックアップ機能を実装する際に
ユーザーのパスワードを保存する方法について
紹介しました。

この方法に気付くまで
私はフルバックアップに
パスワードを含める事が
できませんでした。

気付いた時に大変気持ちよかったため
この気持ちを共有したいと思い
この記事を作成しました。

この記事でフルバックアップを実装する際の問題を
解決できた人が現れたならば幸いです。

皆さんの開発の助けになれますように。
閲覧ありがとうございました。
【テスト技法】Nスイッチカバレッジテスト

# はじめに
こんにちは。アメリカで独学でエンジニアを目指している者です。
現在はRailsを勉強しているのですが、並行してソフトウェアテスト技法も学ぶことで、Railsチュートリアルの理解が深まるのではないかと考え、テスト技法の勉強を始めました。
今回学んだNスイッチカバレッジテストについて、記憶が薄れないうちに簡単にまとめておきたいと思います。
なお、実際の計算については行列計算を伴い複雑のため今回は省略いたします。
ちなみに、これらはUdemyで勉強しています。とても分かりやすくNスイッチカバレッジテストの計算方法もそこで扱っているので、ぜひ見てみてください

https://www.udemy.com/share/102NaE3@Klm5Y802jzOOWemmUmgcZKwsmg5ZeKSLdssOdLltCQUeMwrYsLoBehQBwhoefOb3yw==/

## Nスイッチカバレッジを行う目的

ソフトウェアは、単に単一の入力値や単一の条件分岐を考慮するだけでは不十分なケースが多く、あるイベントが発生した後に続く別のイベントによる影響まで考慮する必要があります。Nスイッチカバレッジは、連続して起こり得るイベントのパターンを一定の深さ（N回の切り替え）まで網羅的にテストすることで、思わぬ組み合わせで発生する不具合を検出しやすくします。

## Nスイッチカバレッジの定義

- **1スイッチカバレッジ (1-Switch Coverage)**
  - 2つの連続する状態遷移・条件分岐をすべてテストする。
- **2スイッチカバレッジ (2-Switch Coverage)**
  - 連続する3つの状態遷移・条件分岐の全組み合わせをテストする。
- **Nスイッチカバレッジ (N-Switch Coverage)**
  - 連続するN+1個の状態遷移・条件分岐の全組み合わせをテストする。

Nの値を大きくするほどテスト量は増えますが、より厳密なカバレッジが期待できます。

## メリットとデメリット

### メリット

- **多様な組み合わせをテスト可能**：単一の条件分岐だけでなく、連続する分岐を網羅的に確認できる。
- **欠陥発見率の向上**：システム内部の状態が連続的に変化するシナリオでのバグを発見しやすくなる。
- **リスク低減**：特に高信頼性が求められるシステムで、思いがけない連鎖的な不具合のリスクを軽減できる。

### デメリット

- **テストケースの増加**：Nを大きくするほど組み合わせが指数的に増えるため、工数やコストが大きくなる。
- **テスト設計の複雑化**：連続する条件をどのように抽出・管理するかが難しく、テスト設計が複雑になる。

## 適用分野と注意点

### 適用分野

- **状態遷移が多いシステム**：例えば、ユーザー認証やワークフローシステムなど、ステップが連続的に変化するシステム。
- **複数の連続操作が前提となる機能**：GUI操作などで、ユーザーが連続して異なる操作を行う可能性がある場合。

## 導入プロセスの例

1. **対象モジュールの明確化**：連続する状態変化をテストすべきモジュールや機能を特定する。
2. **状態遷移表または状態図の作成**：どのような条件やイベントで状態が変化するのか、可視化する。
3. **N値の決定**：どの程度の深さまで網羅すべきか（1スイッチ、2スイッチ、など）を決める。
4. **テストケース生成**：状態遷移表に基づいて、全ての連続したN回分岐を含むパスを導出する。
5. **テスト実行と結果分析**：導出されたテストケースを実行し、問題がないかを検証する。

## まとめ

Nスイッチカバレッジテストは、連続的な状態変化や条件分岐の影響を漏れなくテストするための有効な技法です。とはいえ、テスト範囲が広がる分、テストケースは膨大になりがちです。そのため、開発中のソフトウェアに適したN値を採用することをおすすめします。
etcフォルダってなに？

## はじめに
サーバーを構築する際に、よく目にするetcフォルダですが、いろいろ調べてみると、Linux Foundationという組織が、ドキュメントにまとめて説明していたので、日本語でまとめることにします。
https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s07.html 

## etcフォルダ
etcフォルダーとは、ホスト固有のシステム設定ファイルを格納する場所であり、etcフォルダの中にはバイナリファイルは含まれないです。
また、設定ファイルは、etc/に直接配置するのではなく、サブディレクトリに配置することが勧められています。

具体的なサブディレクトリでいうと以下のようなものがあります。
### /etc/opt
追加のアプリケーションソフトウェアのホスト固有の設定ファイルを格納
### /etc/X11
Window システムに関する設定ファイルを格納
### /etc/sgml および /etc/xml
高レベルの設定パラメータを格納

## 最後に
サーバー構築の際、なぜこのファイルが/etcフォルダー内に配置されているのか、疑問に感じることも多かったのですが、実際にまとめてみるとその意図がよく理解でき、とても納得できました。他にもLinuxのフォルダには興味のあるフォルダがあるので、積極的に調べてみようと思います。