OmniAICreator/Qiita-1.07M huggingface dataset:
固定ヘッダがあるモーダル内でさらに内部ヘッダを固定する方法

## 説明

- `updateInnerHeaderPosition`関数は、外側のヘッダの高さを計算し、内部ヘッダの`top`プロパティを動的に設定します。
- ページが完全に読み込まれたとき（`DOMContentLoaded`イベント）、およびウィンドウがリサイズされたとき（`resize`イベント）にこの関数を呼び出します。
- `MutationObserver`を使用して、外側のヘッダに変更があった場合に関数を呼び出します。これにより、外側のヘッダの高さが動的に変更された場合にも内部ヘッダの位置が自動的に更新されます。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fixed Header in Modal</title>
    <style>
        .modal {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 80%;
            height: 80%;
            background-color: white;
            overflow: auto;
            border: 1px solid #ccc;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        .modal-header {
            position: sticky;
            top: 0;
            background-color: #f1f1f1;
            padding: 10px;
            border-bottom: 1px solid #ccc;
            z-index: 10;
        }

        .modal-content {
            padding: 20px;
        }

        .inner-header {
            position: sticky;
            top: 0; /* JavaScriptで動的に設定されるため初期値は0 */
            background-color: #e1e1e1;
            padding: 10px;
            border-bottom: 1px solid #ccc;
            z-index: 5;
        }

        .content {
            height: 1000px;
        }
    </style>
</head>
<body>
    <div class="modal">
        <div class="modal-header">
            モーダルの固定ヘッダ
        </div>
        <div class="modal-content">
            <div class="inner-header">
                内部の固定ヘッダ
            </div>
            <div class="content">
                スクロールコンテンツがここに入ります。
            </div>
        </div>
    </div>

    <script>
        function updateInnerHeaderPosition() {
            var modalHeader = document.querySelector(".modal-header");
            var innerHeader = document.querySelector(".inner-header");

            if (modalHeader && innerHeader) {
                var modalHeaderHeight = modalHeader.offsetHeight;  // 外側ヘッダの高さを取得
                innerHeader.style.top = modalHeaderHeight + "px";  // 内部ヘッダのtopプロパティを設定
            }
        }

        document.addEventListener("DOMContentLoaded", function() {
            updateInnerHeaderPosition();  // ページロード時に位置を更新

            // ウィンドウリサイズ時に高さを再計算
            window.addEventListener("resize", updateInnerHeaderPosition);

            // モーダルヘッダの高さ変更を監視
            var modalHeader = document.querySelector(".modal-header");
            var observer = new MutationObserver(updateInnerHeaderPosition);
            observer.observe(modalHeader, { attributes: true, childList: true, subtree: true });
        });
    </script>
</body>
</html>
```
AWS DVA 合格体験記

# はじめに
AWS DVA(C02)試験を受験して一発合格できたので、
忘れないうちに学習方法等メモしていきます。

# 受験前のステータス
・AWS実務経験は1年強、ただし小規模案件ばかりであまり深く触ったことはない（マネージドなWeb3層がメイン）
・AWS SAA、SAP、SOA取得済

# 学習の概要
学習時間：10時間程度（平日30分～1時間、休日2～3時間）
学習機関：約1週間
学習方法：Web問題集（CloudTech）＋公式サンプル

# 学習に使用したもの
- **Web問題集（[CloudTech](https://kws-cloud-tech.com/)）**
資格会員4980円/90日間です。
AWS SAPを受けるために購入していたものの期間が残っていたため、そのまま利用。
問題の質は普通に良いです。解説は試験の種別によって担当者が違うのか、SOAは少しわかりづらい印象があったのですが、DVAは割と読みやすく感じました。

- **公式サンプル問題**
公式サイトの試験概要のページに掲載されている[サンプル問題](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-dev-associate/AWS-Certified-Developer-Associate_Sample-Questions.pdf)。
- **公式練習問題**
SkillsBuilder内の「AWS Certified Developer – Associate Official Practice Question Set (DVA-C02 – Japanese)」
20問分を無料で受講できます。

# 学習の流れ
### Web問題集で演習を実施
AWS SAProから4週間、SOAから1週間での受験だったため、基礎知識はある前提で、CloudTechのWeb問題集で演習を開始。
今回も中々やる気が出ずに100問程度解いてタイムアップ。
SOAよりもDVAのほうが正答率や解きやすさはかなり上だったので、安心していたのもあります。

### 公式サンプル問題＋練習問題を解く
公式サンプルは8/10、公式練習問題は16/20。
CloudTechの問題も含めて、安定して8割取れていたので、精神的には割と余裕がありました。

# 受験時の流れ
テストセンターで受験。空調が寒いし乾燥するのでのどが痛くなりました。
Associateなので試験時間は短いですが、とはいえ2時間超集中力を維持するのはしんどい。

なぜかラスト10問近く、出題意図の掴めない問題が連続しており、ちょっと焦りました。

1周終わった時点で残り時間30分、フラグを付けた問題が26個。
見直して5分前に終了。

結果は前回と同じく、2時間半程度でメールが来ました。
今まで受けた試験の中では一番得点が高かったです。

# 難易度
SAP、SOA、DVAと連続して受験しましたが、個人的な難易度は
SAP > SOA > DVA > SAA
でした。

これは私自身が実務で触った経験のあるサービスが多く出題対象になっていたのも大きいと思います。
・S3の静的Webサイトホスティング＋バックエンドAPI開発
　（CloudFront, S3, API Gateway, Lambda, DynamoDB）
・StepFunctionの利用経験
・AWSではないが、基本的なIaCやCI/CDの経験
　（CloudFormationやCodePipelineの仕様が頭に入りやすい）
上記の経験が生きてるな、と感じました。

実務経験がない場合は難易度の感じ方も変わってきそうです。
試験名にDeveloperと入っていることもあり、SAP, SOAでの出題内容よりは具体的な設定方法まで聞かれるので、開発者寄りの試験なことは間違いないと思います。

# 今後に向けて
AWS DOPに挑戦したいのですが、参考書がなさそう＆別の試験も受験予定のため、AWSはしばらく休憩する予定です。（CloudTechの購入期間も終わるし）
とはいえ、CodeCommitがなくなる（なくなった？）影響で試験もそのうち更新されそうなので、変わる前に取ってしまいたいですね。
Javaで「文字列の中でパターンとマッチする部分があるか検索する(Matcher.find)」の動作を確認してみた

# 概要

Javaで「文字列の中でパターンとマッチする部分があるか検索する(Matcher.find)」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/regex/index4.html

# 実装

以下のファイルを作成しました。
```JSample4_1.java
import java.util.regex.*;

class JSample4_1{
  public static void main(String[] args){
    String regex = "[0-9]{2}";
    Pattern p = Pattern.compile(regex);

    Matcher m = p.matcher("CODE24-11-75");
    if (m.find()){
      System.out.println("マッチしました");
      System.out.println(m.group());
    }
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample4_1.java 
$ java JSample4_1 
マッチしました
24
```

以下のファイルを作成しました。
```JSample4_2.java
import java.util.regex.*;

class JSample4_2{
  public static void main(String[] args){
    String regex = "[0-9]{2}";
    Pattern p = Pattern.compile(regex);

    Matcher m = p.matcher("CODE24-11-75");
    while (m.find()){
      System.out.println(m.group());
    }
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample4_2.java 
$ java JSample4_2 
24
11
75
```

# まとめ

何かの役に立てばと。
CloudFront FunctionsでBasic認証を実装する

CloudFront に Basic 認証を設定するとき、いつもは Lambda@Edge を使っていましたが、CloudFront Functions という機能を知り、こちらでも Basic 認証を実装できるので実際に試してみました。Basic 認証の username と password の設定には、CloudFront Functions と連携できる CloudFront KeyValueStore を使用しました。CloudFront KeyValueStore を利用すれば、username や password をコード内にハードコーディングする必要がないので、設定情報とコードを分離させることができ、柔軟に対応することができるようになります。

この記事では、CloudFront Functions の始め方、CloudFrontKeyValueStore とCloudFront Functions の紐づけ等は記載せず、CloudFront Functions での Basic 認証の実装の部分だけ説明します。

## Basic 認証の実装

CloudFront Functions から CloudFront KeyValueStore の値を取り出すために、ヘルパーメソッドが用意されています。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.html

このヘルパーメソッドを使用することで、簡単に CloudFront Functions から CloudFront KeyValueStore のキー値を取り出すことができます。CloudFront KeyValueStore のキー値を利用して Basic 認証の処理を実装したのが下記になります。

```javascript
import cf from 'cloudfront';

const kvsId = '<KEY_VALUE_STORE_ID>';

// This fails if the key value store is not associated with the function
const kvsHandle = cf.kvs(kvsId)

async function handler(event) {
    const request = event.request;
    const headers = request.headers;
    const method = request.method;

    let username = '';
    let password = '';
    try {
        username = await kvsHandle.get('username');
        password = await kvsHandle.get('password');
    } catch (err) {
        console.log(`Kvs key lookup failed: ${err}`);
        throw err;
    }

    const authorization = `Basic ${(`${username}:${password}`).toString('base64')}`;  
    const origin = '*';

    // Preflight requests skip basic authentication
    if (method === "OPTIONS") {
        return {
            statusCode: 204,
            statusDescription: "NoContent",
            headers: {
                "access-control-allow-origin": { value: origin }
            }
        };
    }

    // Handling of authentication fail
    if (headers.authorization === undefined ||
        headers.authorization.value !== authorization) {
        return {
            statusCode: 401,
            statusDescription: 'Unauthorized',
            headers: {
                'www-authenticate': {value: 'Basic'}
            }
        };
    }

    return event.request;
}
```

## 関数のテスト

実装したプログラムは CloudFront Functions のテストタブからテストすることができます。何もテスト設定していない状態でテストすると、実行結果のステータスは ``401 Unauthorized`` になります。Basic 認証を通過するために、ヘッダーに ``Authorization: Basic <username:password を base64 でエンコードした値>``を設定します。username と password を base64 でエンコードした値を作成するためには、以下のようなコマンドで作成が可能です。
``username``と``password``は実際の値に置き換えてください。


```bash
$echo "Basic $(echo -n 'username:passoword' | base64)"
```

出力された文字列をヘッダーの値に入力してテストを実行します。正しく動けば実行結果のステータスは「成功」が表示されます。
Next.js14の環境構築をvoltaとpnpmを使ってサクッと行う

# はじめに
今回は、業務で検証用のアプリの雛形作成をサクッと行いたいなと思い、パッケージのインストールや依存関係の解決が高速(と言われている)`volta`と`pnpm`を使ってNext.js14のプロジェクト作成の手順を備忘録としてまとめました

# 新規プロジェクト作成

```zsh
npx create-next-app@latest

# バージョン指定する場合
npx create-next-app@14.2.3
```

+ Nextのバージョン確認
```zsh
npx next --version
```


# `volta`導入
参考記事: [Node.jsのバージョン管理にVoltaを推したい - Qiita](https://zenn.dev/taichifukumoto/articles/how-to-use-volta)


- JavaScript ツールマネージャー (node.js, npm, yarn のバージョン管理も行うことができる)
- Rust 製であるため、他のバージョン管理ツール(yarn, npm etc.)より動作が高速
- Node.js のバージョンは基本的に LTS(偶数)年度のものを採用

```zsh
brew install volta
```

+ voltaのパス設定
  + システムがvoltaコマンドを認識できるようにする
  + `$HOME/.volta/bin`をPATH環境変数に追加
      + PATHとは、システムがコマンドを探す場所のリスト
  + これにより、voltaとそれを通じてインストールされたpnpmのバイナリファイルがある場所をシステムに教えている
```zsh
export PATH="$HOME/.volta/bin:$PATH"
```

+ `.zshrc`の再読み込み
```zsh
source ~/.zshrc
```

+ voltaのバージョン確認
```zsh
volta -v
```

- Node.js のグローバルデフォルトバージョンを設定する
```zsh
volta install node

# バージョン指定する場合
volta install node@20.13.1
```

- プロジェクトで使用する Node.js のバージョンを固定する

```zsh
volta pin node

# バージョン指定する場合
volta pin node@20.13.1
```

+ nodeのバージョン確認
```zsh
node -v
```

# `pnpm`導入 (performant npm)


- npm, yarn と並ぶ JS のパッケージマネージャー
- 他と比べてインストールなどの動作が高速
    - pnpmは、すべてのパッケージをグローバルストアに保存するので、各プロジェクトは、必要なパッケージへのハードリンクまたはシンボリックリンクを持つことにより、以下の2点のメリットが享受できる
        1. 同じパッケージが複数のプロジェクトで使用されても、1つのコピーだけが保存されるのでディスク容量が節約される
        2. 新しいパッケージをダウンロードする代わりに既存のパッケージへのリンクを作成するだけで済む
    + また、npmやyarnは、依存関係をフラットに解決しようとして時間がかかりますが、pnpmは階層的な構造をしており、各パッケージ毎に`node_modules`フォルダを持ち、意図しない依存関係の使用を防いでくれる
- pnpm を導入した場合、`package-lock.json`の代わりに`pnpm-lock.yaml`というファイルを使用する


- 上記手順でNodeのデフォルトバージョンをインストール後、pnpm をインストール

:::note info
**追記**
以下の記事によると、パッケージマネージャーの中でyarn v4がおそらく最速みたいですね！
:::

https://zenn.dev/minedia/articles/2023-08-30-pnpm

```zsh
volta install pnpm

# バージョン指定する場合
volta install pnpm@9.6.0
```



- プロジェクトの依存関係を pnpm を使ってインストール
  - `package.json`に記載されている依存関係を確認し、必要なパッケージをpnpmのグローバルストアからリンクするorダウンロードする
  - pnpm-lock.yamlファイルを生成
    - 正確なバージョン情報と依存関係のツリーを記録して、再現可能なインストールを保証
  - pnpmの特徴
    - ディスク空間の節約
    - インストールの高速化
    - ->パッケージを一度だけダウンロードして、プロジェクト間で共有する為
```zsh
pnpm install
```

- サーバー起動
```zsh
pnpm run dev
```

## ESLint/Prettierの追加
※今回CSSフレームワークにTailwindCSSを使用しています
```zsh
pnpm add -D prettier eslint-config-prettier prettier-plugin-tailwindcss
```

# 参考記事
https://zenn.dev/taichifukumoto/articles/how-to-use-volta

https://pnpm.io/ja/motivation
C言語の関数をgmockでmock化する方法

こんにちは。
組み込みエンジニアをしているぽぽんたと申します。
初投稿ですので不慣れな部分もございますが、この記事にたどり着いた方のお役に立てれば嬉しいです。

業務中に、C言語の標準関数をgmockを使ってmock化する方法がわからない、という声をよく聞きます。
難しくはないのですが、意外と方法を知らない人が多いのかな、と思い、記事を書くことにしました。

＜2024.08.05 追記＞
以下で説明するstat()は、C言語の標準関数ではなく、POSIX標準の関数ですとのご指摘を頂きました。@yaito3014さん、ご指摘ありがとうございます。
標準関数においても、mock化の方法は変わりませんので、ご参考にしていただければ幸いです。

# 題材：stat()のmock化
この記事では練習として、stat()関数をgmockでmock化してみましょう。

ここではstat()がユーザ定義関数であるIsExist()からコールされているものとします。
IsExist()は引数にファイルのパスを取り、内部でstat()をコールして、ファイルの有無を返します。
最終的なテスト対象はこのIsExist()関数なのですが、この関数をテストするためには、stat()のmock化が必要となります。

```C++:IsExist.h
#ifndef ISEXIST_H_
#define ISEXIST_H_

bool IsExist(const char* path);

#endif  // ISEXIST_H_
```

```C++:IsExist.cpp
#include <sys/stat.h>
#include "IsExist.h"

bool IsExist(const char* path) {
  struct stat st;
  return (stat(path, &st) == 0);
}
```

# stat()のmockを定義する
stat()を差し替えるためのmockクラスとmock関数を定義します。
mock_stat_instanceはmockオブジェクトの実体を格納するためのポインタ変数で、gtestのフィクスチャにて代入するので、ここではnullptrで初期化します。

```C++:mock_stat.h
#ifndef MOCK_STAT_H_
#define MOCK_STAT_H_
#include <sys/stat.h>
#include <gmock/gmock.h>

class MockStat {
 public:
  MOCK_METHOD2(stat, int(const char* path, struct stat* st));
};

extern MockStat* mock_stat_instance;

#endif  // MOCK_STAT_H_
```
```C++:mock_state.cpp
#include "mock_stat.h"

MockStat* mock_stat_instance = nullptr;

extern "C" int stat(const char* path, struct stat* st) {
  if (mock_stat_instance == nullptr) {
    return -1;
  }
  return mock_stat_instance->stat(path, st);
}
```
ここでのポイントは、stat()をmock版として再定義してしまうということです。
この時、stat()に`extern "C"`をつけることを忘れないようにしてください。
また、関数のシグネチャ（引数や戻り値の仕様）は、本物のstat()と合わせてください。

「本物のstat()と2重定義になるのでは？」と思う人もいるかもしれませんが、本物のstat()はlibc.soに実装されており、実行時にリンクされます。
同じコンパイル対象に同じシグネチャの関数が複数あるとエラーになりますが、リンク時に重複するだけなら、先に見つかった方が使用されるため、ここで定義したmock版のstat()が使用されます。

# テストコードを作成する
ここでは、ファイルが見つかった場合と、見つからなかった場合の2パターンをテストしています。
```C++:gtest_IsExist.cpp
#include <gtest/gtest.h>
#include "IsExist.h"
#include "mock_stat.h"

using ::testing::_;
using ::testing::Return;

class StatTest : public ::testing::Test {
protected:
    void SetUp() override {
        mock_stat_instance = &mock_stat_instance_;
    }

    void TearDown() override {
        mock_stat_instance = nullptr;
    }

    MockStat mock_stat_instance_;
};

TEST_F(StatTest, ExistFile) {
  EXPECT_CALL(mock_stat_instance_, stat(_,_))
        .WillOnce(Return(0));

    EXPECT_EQ(IsExist("dummy.dat"), true);
}

TEST_F(StatTest, NoExistFile) {
  EXPECT_CALL(mock_stat_instance_, stat(_,_))
        .WillOnce(Return(1));

    EXPECT_EQ(IsExist("dummy.dat"), false);
}
```

# テストをビルド
下記のコマンドでビルドします。
`g++ gtest_IsExist.cpp mock_stat.cpp IsExist.cpp -lgtest -lgtest_main -lgmock`

# 実行結果
2パターンともPASSしました。
```
[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from StatTest
[ RUN      ] StatTest.ExistFile
[       OK ] StatTest.ExistFile (0 ms)
[ RUN      ] StatTest.NoExistFile
[       OK ] StatTest.NoExistFile (0 ms)
[----------] 2 tests from StatTest (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 2 tests.
```

最後までお読みいただいて、ありがとうございました。
SanctumでLaravel 11とNext.js(v14 App router)を利用した認証機能を実装していく

![Videotogif (8).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2980785/7d002e0e-7149-7fe9-b404-a0d2f08790e7.gif)

## 前提

https://qiita.com/Masanarea_qiita/items/9166258bd6c5b706849d

の記事の続きになりますが、認証機能の実装方法自体はその他の構成でも参考になると思います！

## 実装
上の記事の続きから次の実装を行なってください。

#### 実装内容　
https://github.com/masaaki-imai/origin_dev/pull/1/commits/195fc9e2c50b176d1748ed9befa8e4bdc7291074

実装はGithubの方にまとめているのでそれをそのまま実装してください。

※package.jsonとかpackage_lock.jsonの実装はもちろん行わなくて大丈夫です！

## 画面確認までの準備
実装を終えたら

#### npm インストール
```
docker-compose exec next bash
```
でNext.jsのコンテナに入って、
```
npm install axios humps js-cookie next @mui/material @mui/icons-material
npm install @emotion/react @emotion/styled
npm install --save-dev @types/js-cookie @types/react @types/react-dom @types/node
npm i --save-dev @types/humps
npm i --save-dev @types/js-cookie
```
を実行してください。

#### node_moduleのコピー
ホスト（コンテナの外）で
```
docker cp sys1-nextjs:/app/node_modules ./next/
```
を実行してください。

#### next/.env
next/.env.example　をコピーして next/.envを作ります。

### Laravelの用意
```
docker-compose exec api bash
```
でLaravelのコンテナに入って、
```
php artisan migrate
php artisan db:seed
```
を実行します。

## 準備完了
そうすると以下の画面で動作を確認できるようになります。

## URL一覧(ローカル環境)
- ログインページ
  - http://localhost/user/login
    - メールアドレス：test@example.com
    - パスワード：password
- トップページ
  - http://localhost/user/top

動作としては冒頭のキャプチャと同じですがこんな感じになります。

![Videotogif (8).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2980785/73ae55d5-4714-a819-e2a7-3718ca5da089.gif)
[Mac] クラウドストレージを使ってvimの設定を共有する方法

# 概要

Macを使っていて、複数端末を所有している場合や、端末の乗り換え時に、vimの設定を端末間で共有できると便利だなと思いました。

ここでは、iCloudを活用した方法を説明します。
ディレクトリがローカルのディレクトリにマウントできるもの(例: One Drive, Google Drive, Git)であれば、どんなサービスでも流用可能だと思います。

主な流れは、「iCloudに直接.vimrcファイルを作成→シンボリックリンクを貼る」というシンプルな方法です。

# 前提: クラウドをローカルにマウントできるようにしておく

Macのシステム環境設定からiCloudにサインインし、iCloud Driveをオンにしておく必要があります。

他のクラウドサービスを利用する場合も同様です。

# 作業

## 1. クラウド上にvimの設定ファイル`.vimrc`を作成

Finderやターミナルから、iCloud Driveに移動し、`.vimrc`を作成します。
vimなどのエディタを使って具体的な設定を記述します。

## 2. ローカルのホームディレクトリに`.vimrc`のシンボリックリンクを作成する

ターミナルから以下のコマンドを実行する。

```bash
ln -s ~/Library/Mobile\ Documents/com~apple~CloudDocs/.vimrc ~/.vimrc
```

## 3. 確認

実際になんらかのファイルをvimで開いてみて、設定が適用されていれば完了です。

# 設定を編集したい時は

以降、設定を編集するときは、1で作成したiCloud上の`.vimrc`を編集します。
SwiftとDartの変数､定数宣言､型推論の違い

母語がSwiftとなっているので､メモ

### SwiftとDart比較
Swift
```swift
import Foundation

// 変数の宣言
var myVariable = 42
myVariable = 50

// 定数の宣言
let myConstant = 42

// 型推論による変数の宣言
let inferredInt = 42          // inferredIntはInt型
let inferredDouble = 3.14     // inferredDoubleはDouble型
let inferredString = "Hello"  // inferredStringはString型

// 明示的な型宣言した定数
let explicitInt: Int = 42
let explicitDouble: Double = 3.14
let explicitString: String = "Hello"

// 明示的な型宣言した変数
var name: String = "John"
var age: Int = 30
var isActive: Bool = true


```
Dart
```dart
void main() {
  // 変数の宣言
  var myVariable = 42;
  myVariable = 50;

  // 定数の宣言 (実行時定数)
  final myFinal = 42;

  // 定数の宣言 (コンパイル時定数)
  const myConst = 42;

  // 型推論による変数の宣言
  var inferredInt = 42;          // inferredIntはint型
  var inferredDouble = 3.14;     // inferredDoubleはdouble型
  var inferredString = "Hello";  // inferredStringはString型

  // 明示的な型宣言した定数
  final int explicitInt = 42;
  final double explicitDouble = 3.14;
  final String explicitString = "Hello";
  const String myWord = "Test";

  // 明示的な型宣言した変数
  String name = "John";
  int age = 30;
  bool isActive = true;
}

```
WindowsでLAN内に新しく接続した機器のIPアドレスを調べる

# はじめに
Raspberry Piなどをセットアップし、初回起動時にIPアドレスが解らない場合などにWindows PCから調べる方法のメモです。

# 手順
## PowerShellの起動
PowerShellを管理者モードで起動します。

## 現在のARPテーブルの確認
管理者モードで起動したPowerShellのプロンプトで下記のコマンドを実行し、結果を確認します。
```powershell
PS C:\Windows\system32> arp -a

インターフェイス: 192.168.0.13 --- 0x11
  インターネット アドレス 物理アドレス           種類
  192.168.0.1           xx-xx-xx-xx-xx-xx     動的
  192.168.0.2           xx-xx-xx-xx-xx-xx     動的
  192.168.0.4           xx-xx-xx-xx-xx-xx     動的
  192.168.0.10          xx-xx-xx-xx-xx-xx     動的
  192.168.0.100         xx-xx-xx-xx-xx-xx     動的
  192.168.0.255         ff-ff-ff-ff-ff-ff     静的
  224.0.0.2             xx-xx-xx-xx-xx-xx     静的
  224.0.0.251           xx-xx-xx-xx-xx-xx     静的
  224.0.0.252           xx-xx-xx-xx-xx-xx     静的
  239.255.255.250       xx-xx-xx-xx-xx-xx     静的
  239.255.255.253       xx-xx-xx-xx-xx-xx     静的
```

## ARPキャッシュクリア
次に```arp -d```コマンドを実行しARPキャッシュをクリアします。
その後、再度確認コマンドを実行します。
```powershell
PS C:\Windows\system32> arp -d *
PS C:\Windows\system32> arp -a

インターフェイス: 192.168.0.13 --- 0x11
  インターネット アドレス 物理アドレス           種類
  192.168.0.1           xx-xx-xx-xx-xx-xx     動的
  224.0.0.2             xx-xx-xx-xx-xx-xx     静的
```

## 同じセグメント内のすべてのIPに対しPing
同じセグメント内のすべてのIPに対しPingを打ちます。
ただし、ホームルーターの設定などが確認でき、DHCPで付与するIPが制限されている場合は範囲を限定することができます。
当方の場合、192.168.0.1～129までを範囲にしているので下記のようなコマンドを実行しました。
中カッコ内の-wオプションにはいちホストに対してのpingの送信回数を指定します。
今回は急いでいたので1回にしています。
```powershell
PS C:\Windows\system32> for($i=1; $i -lt 129; $i++){ping -w 1 -n 1 192.168.0.$i; arp -a 192.168.0.$i}


192.168.0.1 に ping を送信しています 32 バイトのデータ:
192.168.0.1 からの応答: バイト数 =32 時間 =3ms TTL=64

192.168.0.1 の ping 統計:
    パケット数: 送信 = 1、受信 = 1、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 3ms、最大 = 3ms、平均 = 3ms

インターフェイス: 192.168.0.13 --- 0x11
  インターネット アドレス 物理アドレス           種類
  192.168.0.1           xx-xx-xx-xx-xx-xx     動的

＜＜＜中略＞＞＞

192.168.0.128 の ping 統計:
    パケット数: 送信 = 1、受信 = 0、損失 = 1 (100% の損失)、
ARP エントリが見つかりませんでした。

```
## 再度ARPテーブルを確認
再度ARPテーブルを確認し追加されたネットワーク機器を確認します。
```powershell
PS C:\Windows\system32> arp -a

インターフェイス: 192.168.0.13 --- 0x11
  インターネット アドレス 物理アドレス           種類
  192.168.0.1           xx-xx-xx-xx-xx-xx     動的
  192.168.0.2           xx-xx-xx-xx-xx-xx     動的
  192.168.0.3           xx-xx-xx-xx-xx-xx     動的
  192.168.0.4           xx-xx-xx-xx-xx-xx     動的
  192.168.0.5           d8-3a-dd-xx-xx-xx     動的
  192.168.0.10          xx-xx-xx-xx-xx-xx     動的
  192.168.0.12          xx-xx-xx-xx-xx-xx     動的
  192.168.0.100         xx-xx-xx-xx-xx-xx     動的
  224.0.0.2             xx-xx-xx-xx-xx-xx     静的
  224.0.0.251           xx-xx-xx-xx-xx-xx     静的
  224.0.0.252           xx-xx-xx-xx-xx-xx     静的
  239.255.255.250       xx-xx-xx-xx-xx-xx     静的
  239.255.255.253       xx-xx-xx-xx-xx-xx     静的
```

# 併せて利用すると便利なサイト
MACアドレス検索
https://uic.jp/mac/address/002bf5/
このサイトでRaspberry Piと検索するとRaspberry PiのMACアドレスのベンダーコード（前６桁）を確認することができます。
【ChatGPT＋Code Interpreter】で時計っぽい感じのもののアニメGIFを作成します。


　どうも、カーブミラーです。

　今回は、時計っぽい感じのもののアニメGIFを作成します。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::

　まずは、ニュース。

　Perplexityが
　　二周年になりました。
　　　[Perplexityポスト](https://x.com/perplexity_ai/status/1819774017848463773?t=ZcnsDQ6_r7inIcYXwfmmNg&s=19)
***
　さて、本題です。

　今回は、
　　時計っぽい感じのものの
　　　アニメGIFを作成します。

　時計というよりも
　　アナログのストップウォッチを
　　　イメージしてもらえれば
　　　　いいかと思います。

　知らないという人も
　　いらっしゃるかもですが😅
　　　今はデジタルオンリーだもんね。
***
　それはさておき、本題に。

　最初、中心点を中心にして
　　回転する黒線をアニメGIFに
　　　していたのですが、
　　　　たまたま時計っぽい動きが
　　　　　出てきたので記事にします😸

　出来上がりがこちら。
![rotating_line_clockwise.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/afd7d14f-e4d7-b12e-248a-399a7995581a.gif)

　ここに至るまでに
　　いろいろとあったのですが、
　　　時計回りを指定したのに
　　　　なぜか反時計回りになる
　　　　　ということが発生しました。

　そんなやり取りをどうぞ。
***
***user***
CodeInterpreterで、白い正方形（512×512）の中央に、中央を軸にした時計の針のように、黒線を時計回りに一回転するアニメGIFを作成してください。
コードは不要です。
不明な点があれば質問してください。

***GPT-4o***
（ダウンロードリンク）

***user***（反時計回りじゃん）
時計回りを指定しましたが、逆回りになっています。
原因を教えてください。

***GPT-4o***
時計回りに見えない原因は、極座標系での角度の増加方向と、画像表示時のY軸の方向が関係しています。通常、極座標系では角度の増加が反時計回りになりますが、画像表示時のY軸が下方向に増えるため、結果的に反時計回りに見えてしまうのです。

これを修正するためには、角度の増加を反転させる必要があります。具体的には、角度を時計回りに増やすために負の値を使います。

修正したコードで再度GIFを作成します。
（ダウンロードリンク）
***
　これで出来上がったのが
　　上記のアニメGIFです。

　なぜ反時計回りになったのか。

　小難しい説明なので
　　言い直してもらいました😅
***
***user***
説明を中学生でもわかるようにお願いします。

***GPT-4o***
わかりやすく説明しますね。

**問題の原因**:
- 反時計回りに見える理由は、数学では角度が増える方向が反時計回りになっているからです。
- 画像では上が0度で、右が90度、下が180度、左が270度となり、通常の角度の増え方（正の角度）が反時計回りになります。

**解決方法**:
- 時計回りにしたい場合、角度を減らす（負の角度を使う）ようにすれば良いです。

***user***
この原因の説明だと、時計回りになると思われますが？

***GPT-4o***
確かに、説明が誤解を招くものでした。正確には以下のように説明します。

**原因の説明**：
- 通常、数学では角度が増える方向が反時計回りになります。
- プログラムで線を描くとき、角度が増えると線が反時計回りに回転します。

しかし、今回の場合では、**画像のY軸が上に行くほど値が小さくなるため、反時計回りに見えてしまいます**。これは、通常の座標系とは逆の動きをするためです。

**修正方法**：
- 角度の増え方を負の方向にする（角度が減るようにする）ことで、線が時計回りに動くようになります。

これにより、線が時計回りに回転するアニメーションGIFを作成することができました。

***user***（これは前提条件が必要だね）
前提条件から説明してください。

***GPT-4o***
わかりました。最初から順を追って説明します。

### 前提条件

1. **座標系**:
    - 画像の座標系では、左上が (0, 0) で、右下に行くほどX軸とY軸の値が大きくなります。
    - 通常の数学の座標系とは異なり、Y軸の値が増える方向が下になります。

2. **角度**:
    - 数学的には、角度が増える方向（正の角度）は反時計回りです。
    - 0度は右方向、90度は上方向、180度は左方向、270度は下方向です。

### 問題の原因

アニメーションを作成する際に、角度を増やしていくと、通常の数学的な定義に従って線が反時計回りに回転します。しかし、画像の座標系ではY軸が上下逆なので、結果的に反時計回りに見えます。

### 解決方法

時計回りに見せるためには、角度を増やすのではなく、減らす（負の角度を使う）必要があります。これにより、線が時計回りに回転するように見えます。

### 実際の修正

具体的には、36フレームで1回転するアニメーションを作成する際に、角度を0度から360度まで増やすのではなく、0度から-360度まで減らしていくようにしました。

この方法で修正した結果、線が時計回りに回転するアニメーションGIFを作成することができました。
***

　まぁ、こんな感じです。

　座標系を意識して
　　指示を出さないと
　　　今回のようなことになる、
　　　　という話でした。

　これは
　　ChatGPTが吸収して
　　　最初から出して欲しい
　　　　問題ではありますが
　　　　　Code Interpreterを
　　　　　　指定した時点で、
　　　　　　　そうした考慮が
　　　　　　　　なくなるのでしょう。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
【初心者向け】SQLクエリの句　抽出順番について

今回の記事は「SQLの抽出順番を理解することでそれぞれの句の意味がすんなり理解できるかも」というお話。

まずSQLの句ってどんなものがあるか見ていきましょう。
上から記載する順番に見ていきます。

```
句の種類について
①SELECT句: 抽出する列を指定
②FROM句: データを取得するテーブルを指定
③WHERE句: 行のフィルタリング条件を指定
④GROUP BY句: 行をグループ化する列を指定
⑤HAVING句: グループ化後にグループをフィルタリングする条件を指定
⑥ORDER BY句: 結果セットを並べ替える条件を指定
```

具体的なコード
```SQL
SELECT 店舗名, SUM(売上) AS 総売上 --「店舗名」と「総売上」を表示する。
FROM 売上テーブル　--「売上テーブル」から見つける。
WHERE 地域 = '関東' --「地域」というカラム（列）に「関東」と含まれている場所を見つける。
GROUP BY 店舗名 --「店舗名」の順番でグループ化。
HAVING SUM(売上) > 100000 --「総売上」は「100000」以上という条件。
ORDER BY 総売上 DESC; --売上が高い順で表示する。
```

コメントを見ると「なんとなくわかる」という状態だと思います。
しかし、実際に書いてみると「どの句からかいたらいいかわからない」という状態になると思います。自分はなりました。

そこで以下の方法で処理が進むと分かれば、記載のポイントを理解することが出来るのではないでしょうか？


```
処理の順番
①FROM --テーブルからデータを取る
②WHERE --データを取る場所
③GROUP BY --グループ化
④HAVING　--フィルタリング条件を指定
⑤SELECT --表示する項目
⑥ORDER BY --表示する項目の順番
```

「まって、GROUP BY とHAVINGって同じじゃね？似てね？」
って僕は思いました。

説明すると、
```
GROUP BY はグループ化。
HAVING はグループ化後の結果に条件を設定。
```
つまり先程のSQL文で説明すると
```
単純なグループ化と集計：
店舗ごとに売上の合計を出したい → GROUP BY
集計結果に基づくフィルタリング：
売上の合計が特定の金額以上の店舗を知りたい → GROUP BYとHAVING
```
という感じです。
グループした後に覆うような形で更に条件を加える場合に「HAVING」を使うというイメージです。

以上、ご覧いただきありがとうございました。
ラズパイ５に非推奨になったWiringPiのpythonライブラリをインストール

# ラズパイ５にWiringPi Pythonライブラリをインストール
まず最初に下記の記事でWiringPiのCライブラリをイントール（コンパイル）しておきます。

[ラズパイ５に非推奨になったWiringPIをインストール](https://qiita.com/kawamo55/items/35f3965692cea28aa03d)

次にgit clone https://github.com/WiringPi/WiringPi-Python
をCのソースディレクトリと同列に見える部分にクローンします。

cd WiringPi-Python
に移動します。

rm -rf WiringPi
でフォルダを消します。

ln -s ../WiringPi .
でシンボリックリンクを貼ります。

apt install swig
で必要なものをインストールして

python setup.py install
でインストールします。

# インポートできるかテスト！
pythonを起動して
import wiringpi
でエラーが出ないので大丈夫っぽい

# 追記
gitの更新履歴を見る限り２４年５月１４日まではメンテナンスされている。

ReadMeを見る限りメンテナンスしてくれくる人が見つかったようでまたライブラリのサポートが復活する可能性がありそうです。

新しいOSではどのラズパイでもインストールはできなくなっていますが、
他のラズパイについても同じ手順でインストールできるはず。
AWS Budgets

# はじめに
この記事はAWS SAA試験勉強のための、AWS Budgetsに関する知識のまとめです。

# AWS Budgetsとは

AWS BudgetsはAWS上で使用している各種リソースの使用状況を監視して、アラート設定した金額に近づいた、または超えた場合は通知してくれるサービスです。

# SCPとの組み合わせ

Organizationsで新たなリソースのプロビジョニングを制限するSCPを設定し、Budgetsで予算のしきい値を超えたときに、設定したSCPを自動的に付与することができます。
非メンバ非フレンド関数をつかって結合度を削減しよう

## はじめに
[C++ソフトウェア設計](https://www.oreilly.co.jp/books/9784814400454/) ではprivateなメンバ関数をテストするために、private な関数をフリー関数（自由関数、外部関数）にすることを紹介しています。正直なところ「本気かよ！」となったので、参考文献に挙げられていた[Effective C++ 第3版](https://www.maruzen-publishing.co.jp/item/?book_no=294734)をはじめ他の文献でも触れられていました。それぞれで表現が異なりますが、結合度を削減することを重視していることが分かります。

これまではカプセル化を重視してメンバ関数として定義するか悩むことがあったのですが、堂々と非メンバ関数として定義していけます。

## [Effective C++ 第3版](https://www.maruzen-publishing.co.jp/item/?book_no=294734) 
「23 項 メンバ関数より、メンバでもfriendでもない関数を使おう」に下記記載があります。
> メンバ関数より、メンバでもfriendでもない関数を使おう。それによって、カプセル化の度合いが増し、柔軟性と機能拡張性を持たせることになる。

## [C++Coding Standards: 101のルール、ガイドライン、ベストプラクティス](https://www.amazon.co.jp/C-Coding-Standards%E2%80%95101%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB%E3%80%81%E3%82%AC%E3%82%A4%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%80%81%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9-%E2%80%90depth/dp/4894716860)
「44\. 非メンバーかつ非friend の関数を書くようにしよう」に下記記載があります。
> **メンバー会費を避けよう**：できるだけ関数を非メンバーかつ非friendにしよう

さらに関数をメンバーかfriendにすべきかを決定するアルゴリズムも記載されています。


## [C++のためのAPIデザイン](https://www.sbcr.jp/product/4797369151/)
「2\.5\.2\. クラス結合度の削減」に下記記載があります。
> 選択できるなら、関数宣言はメンバ関数ではなく非メンバ非フレンド関数として宣言すべきだ。こうすれば、カプセル化が強化され、関数のクラスへの結合度を削減できる。

## [C++ソフトウェア設計](https://www.oreilly.co.jp/books/9784814400454/)
「ガイドライン4：テスト可用性に備え設計する」でprivate メンバ関数をテストする方法の「真の解」としてprivate メンバ関数をフリー関数（自由関数、外部関数）にすることを挙げています。

## [C++ Core Guidelines](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#main)
[C.4: Make a function a member only if it needs direct access to the representation of a class](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c4-make-a-function-a-member-only-if-it-needs-direct-access-to-the-representation-of-a-class) で

## [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
staticなメンバ関数を使うより、非メンバ関数を勧めています。
[Nonmember, Static Member, and Global Functions](https://google.github.io/styleguide/cppguide.html#Nonmember,_Static_Member,_and_Global_Functions)に下記記載があります。
> Do not use a class simply to group static members.


## 参考文献
### 書籍
1. [C++ソフトウェア設計](https://www.oreilly.co.jp/books/9784814400454/)
1. [Effective C++ 第3版](https://www.maruzen-publishing.co.jp/item/?book_no=294734)
1. [C++Coding Standards: 101のルール、ガイドライン、ベストプラクティス](https://www.amazon.co.jp/C-Coding-Standards%E2%80%95101%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB%E3%80%81%E3%82%AC%E3%82%A4%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%80%81%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9-%E2%80%90depth/dp/4894716860)
1. [C++のためのAPIデザイン](https://www.sbcr.jp/product/4797369151/)
1. [リファクタリング（第2版）](https://www.ohmsha.co.jp/book/9784274224546/)
### そのほか
1. [C++ Core Guidelines](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#main)
1. [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
1. [フリー関数を活用しよう](https://www.little-cuckoo.jp/entry/20060511/1147294093)
1. [C++のためのAPIデザイン 読書メモ 第2章 その3](https://qiita.com/tossibility/items/9b0e7b4e29085b2aad8d)
5 つの文字列の半角スペース区切りでの分割 

>5 つの文字列の半角スペース区切りでの分割し、１行ずつ出力する問題をRubyを使って解きました

```ruby
array1 = ["one","two","three","four","five"]
for str in array1 do
    puts str
end

```

出力結果
```
one
two
three
four
five
```
【Android】繰り返し書くことの多い実装はライブテンプレート機能を使おう

# はじめに
日常的に業務を進めていると、同じ実装を何度も実装したりすることありますよね。
その都度コピペしたりして、ただ部分的に特殊な実装が挟まったりするとまたコピペが必要になるなど繰り返しが多ければ多いほど無駄な時間を浪費しがちです。
そこで繰り返し同じ実装を行う場合にはAndroidStudioのライブテンプレート機能を使うと便利です、今回はこのライブテンプレートに関してまとめておこうと思います。

# ライブテンプレート機能とは？
ライブテンプレート機能は、Android StudioおよびIntelliJ IDEAで提供される便利な機能で、特定のコードスニペットを簡単に挿入するためのツールです。
この機能を利用することで、コードの入力を効率化し、よく使うコードパターンを標準化することができます。

実はこの機能、2015年6月にリリースされたAndroid Studio v1.2.2から利用可能で結構古くからある機能です。

# ライブテンプレートの設定方法
ライブテンプレートを設定する為にはまず `Android Studio > Settings` より設定画面を表示します。

次に以下の画像を参考に `Editor > Live Templates` より表示するか、検索窓より`Live Templates`と検索することで表示可能です、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/248d85ea-9568-c2a1-00b5-d47a3a9190b5.png" width="620px">

Live Templates設定欄を表示したら、まず追加したい言語を選択してからプラスアイコンより `Live Template`を選択し、テンプレート内容を設定していきます。
追加したい言語を選択していない状態で追加するとuserという枠が作成され、そこにテンプレートが追加されます。

![スクリーンショット 2024-08-04 10.32.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/3f2f01e9-be09-f14a-5b44-41515522dc18.png)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/527ceb22-5c85-bdc0-8ef8-a84a05e54b0d.png" width="620px">

ライブテンプレートを設定する際には3箇所設定が必要な事項があります。

- **Abbreviation:** ショートカットキーを入力します。このキーを入力するとテンプレートが展開されます
- **Description:** テンプレートの説明を入力します。これはテンプレートの用途を簡単に説明するためのものです
- **Template Text:** 実際のコードスニペットを入力します。変数を使用する場合は、`$VAR$`のように書きます

変数を使用する場合は、EditVariablesより変数を登録する必要があります。

![スクリーンショット 2024-08-04 10.44.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/eb0e9dd3-01a8-6da4-851e-7b28637908d7.png)

必要な情報を下記を参考にテンプレートとして登録し、設定を反映させることで使用可能になります。

![スクリーンショット 2024-08-04 10.41.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/cc13be59-d9b1-0c0a-9726-bcfe5a9e8baa.png)

ご説明は以上になります。

# さいごに
8月ってお盆がある関係で思いの外時間がなくて忙しくなりがちですね、、、
ラズパイ５に非推奨になったWiringPIをインストール

# ラズパイ５にWiringPIをインストール
ラズパイのGPIOとしてもPythonライブラリとしても完璧な動作をしていたWiringPiが非推奨となりちょっとショックを受けていたがどうもGit上のソースを覗いてみるとラズパイ５にも対応しているようだったのでテストしてみることにしてみた。

# まずはソースのインストール
git上で公開されているので
git clone https://github.com/WiringPi/WiringPi
でCのライブラリとgpioコマンドがインストールできるようになる。

もちろん、他のラズパイについても同じ手順で行けるはず。

# インストール
cd WiringPi
でソースのディレクトリに移動する
./build
でコンパイルされライブラリとgpioコマンドがインストールされる

# gpioコマンドで検証
```
gpio  readall
 +-----+-----+---------+------+---+---Pi 5---+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 |   -  | 0 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 |   -  | 0 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   -  | 0 |  7 || 8  | 0 |  -   | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 0 |  -   | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   -  | 0 | 11 || 12 | 0 |  -   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |   -  | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |   -  | 0 | 15 || 16 | 0 |  -   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 |  -   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI |   -  | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   -  | 0 | 21 || 22 | 0 |  -   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK |   -  | 0 | 23 || 24 | 0 |  -   | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 0 |  -   | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   -  | 0 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   -  | 0 | 31 || 32 | 0 |  -   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   -  | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   -  | 0 | 35 || 36 | 0 |  -   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   -  | 0 | 37 || 38 | 0 |  -   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 |  -   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 5---+---+------+---------+-----+-----+
```
どうも動いているぽいのでLチカしてみる。
```
gpio -g mode 17 output
gpio -g write 17 1
```
でLEDが点灯

```
gpio -g write 17 0
```
でLEDが消灯
動作確認できました。

Pythonライブラリもこの分だと行けそうでソース同じgitで公開されてます。
Python `operator.itemgetter`を使って複数のキーでソートする

## はじめに

Pythonでリストやタプルをソートする際、複数の条件に基づいてソートしたいことがあります。例えば、従業員のリストを年齢で昇順にソートし、同じ年齢の場合は給与で降順にソートするといったケースです。このような複雑なソートを簡単に実現する方法として、`operator.itemgetter`関数を使用する方法があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/56c1a37c-9556-51e2-acc5-49065514ca5a.png)


## `operator.itemgetter`とは

`operator.itemgetter`は、Pythonの標準ライブラリ`operator`モジュールに含まれる関数です。この関数は、与えられたインデックスやキーに基づいてオブジェクトから項目を取得する関数を返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/eaa6a20e-dac4-0ba1-ba34-6ff89d013ce7.png)

## 基本的な使い方

まず、単一のキーでソートする基本的な例を見てみましょう。

```python
from operator import itemgetter

# 名前と年齢のタプルのリスト
people = [('Alice', 25), ('Bob', 30), ('Charlie', 22)]

# 年齢でソート
sorted_people = sorted(people, key=itemgetter(1))
print(sorted_people)
# 出力: [('Charlie', 22), ('Alice', 25), ('Bob', 30)]
```

この例では、`itemgetter(1)`を使って各タプルの2番目の要素（年齢）に基づいてソートしています。

## 複数のキーでソートする

`itemgetter`の真価は、複数のキーでソートする際に発揮されます。

```python
from operator import itemgetter

# 名前、年齢、給与のタプルのリスト
employees = [
    ('Alice', 30, 50000),
    ('Bob', 25, 60000),
    ('Charlie', 30, 55000),
    ('David', 25, 55000)
]

# 年齢で昇順、給与で降順にソート
sorted_employees = sorted(employees, key=itemgetter(1, 2), reverse=True)
print(sorted_employees)
# 出力: [('Charlie', 30, 55000), ('Alice', 30, 50000), ('Bob', 25, 60000), ('David', 25, 55000)]
```

この例では、`itemgetter(1, 2)`と`reverse=True`を使用しています。これは以下のように解釈されます：

1. まず、各タプルの2番目の要素（インデックス1、年齢）でソート
2. 年齢が同じ場合、3番目の要素（インデックス2、給与）でソート
3. `reverse=True`を指定することで、全体を降順にソート

結果として：
- Charlieが最初（30歳で高い給与）
- Aliceが次（30歳で低い給与）
- Bobが3番目（25歳で最高給与）
- Davidが最後（25歳で低い給与）

注意：`itemgetter(1, -2)`のような負のインデックスを使用すると、予期せぬ結果になる可能性があります。代わりに、明示的なインデックスを使用することをお勧めします。

## 辞書のリストでの使用

`itemgetter`は辞書のリストをソートする際にも非常に便利です。

```python
from operator import itemgetter

books = [
    {'title': 'Python入門', 'author': '山田太郎', 'year': 2020},
    {'title': 'データ分析実践', 'author': '佐藤花子', 'year': 2019},
    {'title': '機械学習の基礎', 'author': '田中次郎', 'year': 2020}
]

# 出版年で昇順、タイトルでソート
sorted_books = sorted(books, key=itemgetter('year', 'title'))
for book in sorted_books:
    print(f"{book['year']} - {book['title']} by {book['author']}")

# 出力:
# 2019 - データ分析実践 by 佐藤花子
# 2020 - 機械学習の基礎 by 田中次郎
# 2020 - Python入門 by 山田太郎
```

この例では、まず出版年で昇順にソートし、同じ年の本はタイトルのアルファベット順でソートしています。

## まとめ

`operator.itemgetter`を使用することで、複雑なソート条件を簡潔に記述できます。これは特に、大量のデータを扱う際や、ソート条件が動的に変更される可能性がある場合に非常に有用です。Pythonのソート機能と組み合わせることで、効率的で読みやすいコードを書くことができます。

ただし、複雑なソート条件を使用する際は、意図した結果が得られているか常に確認することが重要です。特に、負のインデックスの使用には注意が必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/38c8c039-65b7-5476-b89b-bc121eab13e8.png)


## 参考リンク：
- [Python公式ドキュメント - operator モジュール](https://docs.python.org/ja/3/library/operator.html)
- [Python公式ドキュメント - ソートHOWTO](https://docs.python.org/ja/3/howto/sorting.html)
- [Python公式ドキュメント - 組み込み関数 sorted()](https://docs.python.org/ja/3/library/functions.html#sorted)
JakartaEEで最適なデバッグ環境とは？

## JakartaEEで最適なデバッグ環境とは？

### はじめに
JavaのWebアプリケーションの開発では、SpringFWの場合はシンプルです。
主流だったSTSがあったり、EclipseにSpringプラグインがバンドルされていたり、EclipseがTomcatをバンドルしていたり、そもそもSpringBootの場合はTomcatが内包されていたり。
一方、JakartaEEは大きな仕様変更で、商用の開発手法が定着していないように感じます。
ということで、少しJakartaEEの開発手法とりわけデバッグ環境が足元必要な状況なのでまとめてみます。

### 統合開発環境 (IDE):
やはり、まずはIDE。

- **IntelliJ IDEA** : Jakarta EEプロジェクトに非常に適しています。内蔵のデバッガ、リファクタリングツール、コード補完機能などが強力です。
- **Eclipse IDE**: Jakarta EEプロジェクトをサポートする多くのプラグインがあり、無料で利用できます。
- **NetBeans**: 直感的なユーザインタフェースと優れたデバッガ機能を提供します。

直球はIntelliJですかね。
Eclipseはプラグインなどデバッグ環境を作るまでに少しありそうです。

### アプリケーションサーバ:

商用利用だとライセンス契約ありのアプリケーションサーバがあるかもしれないので、個人的に使うだけなら商用版のついになる非商用版を使うのがよさそう。
（WebLogicはJakartaEEに対応されるのか・・・）

- **WildFly**: 高速で柔軟なJava EEアプリケーションサーバです。IntelliJ IDEAやEclipseと簡単に統合できます。
- **GlassFish**: Jakarta EEのリファレンス実装であり、多くの開発者が使用しています。
- **Payara Server**: GlassFishをベースにした商用サポートのあるサーバです。

WildFlyのIDEとの統合はいいですね。

### デバッグツールとプラグイン:

**Remote Debugging**: IDEからリモートデバッグを設定することで、アプリケーションサーバ上で実行中のアプリケーションをデバッグできます。ほとんどのIDEはこの機能をサポートしています。
**Maven/Gradle Plugins**: Jakarta EEプロジェクトのビルドとデプロイを簡単にするためのプラグインを利用します。これにより、ビルドプロセスの自動化が可能になります。

デバッグ環境の要は**Remote Debugging**になりそう。

### ユニットテストと統合テスト:

**JUnit**: ユニットテストに使用します。
**Arquillian**: Jakarta EEアプリケーションの統合テストをサポートします。異なるコンテナ上でテストを実行でき、実際の実行環境に近いテストが可能です。

### ログとモニタリング:

単体テストあたりだと不要ですが、結合テスト環境以降のデバッグだと重要になってきますね。

**ログフレームワーク**: SLF4JやLogbackを使用して、アプリケーションのログを管理します。
**監視ツール**: VisualVMやJConsoleなどのツールを使用して、JVMのパフォーマンスをモニタリングします。

### コンテナとオーケストレーション:

デバッグ環境の効率化なども考えて、コンテナも視野に入れておきたいところです。

**Docker**: アプリケーションサーバをDockerコンテナとして実行し、開発環境を容易に再現可能にします。
**Kubernetes**: 大規模なデプロイメント環境で使用されるオーケストレーションツールです。複数のコンテナを管理するのに役立ちます。

### 最後に

これらの要素を考えて、最適なデバッグ環境を構築することが大切と考えます。具体的なセットアップ方法は、上記のツールと方法を調査や検討して、効率的で効果的な開発環境を整えることが必要です。

私は以下のように進めよう。
1. WildFly。EclipseでJakartaEE＋WildFlyのプラグイン周りを調査、デバッグ環境構築
2.  1が時間がかかりそうなら、Eclipseは止めてIntelliJ に舵を切る。
Spring Boot+Thymeleafではじめの一歩

# プロジェクト作成
[Spring Initializer](https://start.spring.io/;)を使用してSpring Bootのプロジェクトを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520112/79dd64b9-b6a0-ad1d-1b9f-83cb3242c566.png)

依存関係には以下を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520112/f00cc64c-837c-d6f4-bcda-9eee0c996415.png)

Generateを押してダウンロードしたファイルを解凍しておきます。

IntelliJでプロジェクトを開きます。

右下に通知が出てくるのでロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520112/68502f6f-5628-f18d-2aeb-49a0b4276e50.png)

# ページ作成
コントローラを作成します。
```java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class DemoController {

    @GetMapping("/")
    public String demo() {
        return "demo";
    }
}
```

表示するページを作成します。
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello, Spring!</title>
</head>
<body>
    <h1>Hello, Spring!</h1>
</body>
</html>
```

# プロジェクトの実行
DemoApplicationを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520112/4debc0e0-8cc8-3236-6591-e09cb18d66a1.png)

localhost:8080にアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520112/5f6f2d58-bd59-d997-9d36-47562f7be76b.png)

# まとめ
Spring BootでThymeleafを使って簡単にページを作成することができました。
初心者向けPythonのドキュメントやログ処理について気をつけたいこれだけのこと

## Pythonにはログの取り方がいろいろ用意されてます！

こんにちは、Pythonプログラマーの皆さん！今日は、Pythonでログ機能を実装する方法について、楽しく学んでいきましょう。ログは開発中のデバッグや、本番環境での問題解決に欠かせない重要なツールです。さあ、一緒にPythonのログの世界を探検しましょう！

## ログの基本

Pythonには標準ライブラリに`logging`モジュールが用意されています。これを使えば、簡単にログ機能を実装できます。

```python
import logging

# ログの基本設定
logging.basicConfig(level=logging.INFO)

# ログの出力
logging.info("こんにちは、ログの世界へようこそ！")
```

このコードを実行すると、次のような出力が得られます：

```
INFO:root:こんにちは、ログの世界へようこそ！
```

## ログレベルの活用

ログには異なるレベルがあります。主なものは以下の通りです：

- DEBUG
- INFO
- WARNING
- ERROR
- CRITICAL

これらを使い分けることで、ログの重要度を表現できます。

```python
import logging

logging.basicConfig(level=logging.DEBUG)

logging.debug("デバッグ情報です")
logging.info("通常の情報です")
logging.warning("警告です！")
logging.error("エラーが発生しました")
logging.critical("致命的なエラーです！")
```

## ログのフォーマットカスタマイズ

ログの出力形式は自由にカスタマイズできます。日時や行番号など、必要な情報を追加しましょう。

```python
import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

logging.info("カスタマイズされたログです")
```

出力例：

```
2024-08-04 12:34:56 - INFO - カスタマイズされたログです
```

## ファイルへのログ出力

コンソールだけでなく、ファイルにもログを出力できます。

```python
import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    filename='app.log',
    filemode='w'
)

logging.info("このログはファイルに保存されます")
```

このコードを実行すると、`app.log`というファイルが作成され、そこにログが書き込まれます。

## 複数のハンドラの使用

コンソールとファイルの両方にログを出力したい場合は、複数のハンドラを使用します。

```python
import logging

# ルートロガーの作成
logger = logging.getLogger()
logger.setLevel(logging.INFO)

# ファイルハンドラの作成
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.INFO)

# コンソールハンドラの作成
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

# フォーマッタの作成
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# ハンドラをロガーに追加
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# ログの出力
logger.info("このログはファイルとコンソールの両方に出力されます")
```

## まとめ

Pythonのログ機能を使いこなすことで、アプリケーションの動作を詳細に把握し、問題解決を迅速に行うことができます。ぜひ、自分のプロジェクトにログ機能を取り入れて、デバッグ作業を効率化してみてください。

ログ機能の実装は、プロフェッショナルなPythonプログラマーへの第一歩です。これからも、Pythonの素晴らしい機能を探求し続けましょう！
ソフトウェアテスト書籍の出版および同内容のUdemyコースリリースのお知らせ

### 自己紹介

皆さん、こんにちは、Udemy講師の斉藤賢哉です。私はこれまで、25年以上に渡って企業システムの開発に携わってきました。特にアーキテクトとして、ミッションクリティカルなシステムの技術設計や、Javaフレームワーク開発などの豊富な経験を有しています。様々なセミナーでの登壇や雑誌への技術記事寄稿の実績があり、また[「アプリケーションアーキテクチャ設計パターン」](https://amzn.asia/d/9avaCyF)といった書籍も執筆しています。

### ソフトウェアテストに関する書籍を出版します

今般、技術評論社様から「Javaによる～ソフトウェアテスト実践入門～生成AI時代のテスト技法を学ぶ（仮）」を出版することとなりました。現在は最終の校正作業中で、順調にいくと10月ごろには書店に並ぶ予定ですが、出版日が確定したらここでもお伝えしたいと思います。

この書籍は、ソフトウェアテストの基本的な考え方から始まり、JUnit 5を中心としたJavaベースの様々なテスティングフレームワークの利用方法を詳細に解説します。
- **JUnit**：xUnitテスティングフレームワーク
- **Mockito**：モッキングフレームワーク
- **DBUnit**：DBテスト効率化のためのJUnit拡張ライブラリ
- **Spring Boot Test**：Spring BootのためのJUnit拡張ライブラリ
- **RestAssured**：RESTサービスのためのテストライブラリ
- **WireMock**：モックHTTPサーバー作成ライブラリ
- **Selenium**（**Selenide**）：WebブラウザのUIテスト自動化フレームワーク
- **Gatling**：負荷テストフレームワーク

主にJavaエンジニア向けですが、ソフトウェアテストの考え方や技法は、言語を問わずに参考にしてもらえると思います。
またAppendix（補足）として、**GitHub ActionsによるCI/CDパイプラインの構築方法**や、**Chat GPTを活用したテスト効率化手法**についても取り上げます。

### 書籍と同内容のUdemyコース『Javaテスト基礎＆実践』リリースのお知らせ

上記書籍と同内容のUdemyコース「現役アーキテクトが教える『Javaテスト基礎＆実践』」を先日リリースしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597954/924d0152-812b-4bca-dd2a-be521e59f218.png)

ちょうど昨年、ウィーンの美術史美術館でブリューゲルの『バベルの塔』を見てきたこともあり、ソフトウェアテストのイメージにも合うので、全体のモチーフとして使っています。

このUdemyコースの内容は、上記書籍とほとんど同じです。
そしてコースの「売り」の一つが、開発環境全部入りの仮想マシンがOracle VM VirtualBoxの仮想マシンとして提供されるという点です。本コースの開発環境は、仮想マシンとしてUbuntu（22.04 LTS）上に構築されています。この仮想マシンをVirtualBox上で動作させると、以下のリソース一式を、セットアップされた状態ですぐに使うことが可能です。

* ソースコード一式（講義で用いたコードを含む）
* JDK（JDK 21）
* 統合開発環境（日本語化対応済みのEclipse）
* 各種ライブラリ（JUnit 5、Mockito、DBUnit、RestAssured、WireMock、Selenideなど）
* 負荷テストツール（Gatling）
* データベース（MariaDB）※MySQL互換
* Spring Bootによるサンプル用Webアプリケーション

本コースのソースコードは講師のGitHub上で公開していますので、それを使って個別に開発環境をセットアップすることも可能ですが、難易度が高く手間も相応にかかります。その点、この方法であれば特段のスキルは不要であり、手間もそれほどかかりません。

### Udemy講座のクーポンコード（2024年8月末まで）

上記の『Javaテスト基礎＆実践』も含めて、現在私が講師を務めるUdemy講座には、以下のラインアップがあります。
これらのコースは、**Udedmyセールス対象外のためタイミングを気にすることなく購入可能**です。また以下のリンクから購入いただくと、クーポンが適用されたことになり、定価の**約30%OFF**で購入することができます。
|コース名|リリース|定価|クーポン適用後価格|2024年8月末まで使えるクーポンリンク|
|--|--|--|--|--|
|**『Java Basic編』**|2023年6月リリース済|4,200円|3,000円|https://www.udemy.com/course/learn-java-se-basic/?couponCode=0B5720CBDBF25E9FAF39|
|**『Java Advanced編』**|2023年9月リリース済|3,600円|2,500円|https://www.udemy.com/course/learn-java-se-advanced/?couponCode=B4BDF49E9A6A8080C561|
|**『Java テスト基礎＆実践』**|2024年7月リリース済|4,200円|3,000円|https://www.udemy.com/course/learn-java-testing/?couponCode=4424C7F0F0FBA95A082E|

なお上記クーポンは期限が切れ次第、定期的に発行し、都度別のQiita記事として投稿する予定です。ぜひご活用いただけると幸いです。

### Udemyコース今後の予定

今後の計画を含めて、シリーズ全体のラインアップは、以下図のように考えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597954/1670e242-de1c-51a3-5c4a-2b967d3fc64f.png)

この9月からは新コースとして「Spring Boot3基礎＆実践」「Webの仕組み入門」「Java DBアクセス基礎＆実践」を3本並行で制作に取り掛かる予定です。
いずれも2025年3月ごろのリリースを予定していますので、興味のある方はぜひご検討ください。
合格者が語る！AWS SysOpsアドミニストレーターアソシエイト（SOA-C02）を目指すべき人の特徴

# はじめに
先日、AWS SysOpsアドミニストレーターアソシエイト（SOA-C02）を合格しました。

資格勉強の過程で学ぶことができるサービスの特徴から、SOAを勉強するべきエンジニアの特徴をまとめていきます！

# SOAを勉強するべきエンジニアの特徴
## 特徴
**AWSの業務経験がないが、CLF、DVAが取得できる相当の知識がある方**です！！

## 理由
 SOAは主に以下のサービスが勉強対象になると思います。
 - CloudWatch
 - Systems Manager
 - AWS Config
 - EventBridge
 - CloudFormation

SOAの勉強を行うことで、AWS環境や各リソースの監視やロギング、アラートやIaCの仕組みづくりなど、業務に有用なことを勉強することができます。

趣味などで軽くAWSを触る中では触れない分野でもあるので、業務経験のない方にはかなり勉強になると思います（自分もかなり勉強になりました。AWS Configが好きです）。

逆に、業務でAWSを利用している方には物足りない勉強になる可能性があると感じました。
資格報奨金制度がある方はサクッと取得すると良いかもしれません。

# おわりに
読み返したら当たり前のことしか書いてない気もしますが、せっかく合格したので、勉強した内容を振り返りながらこんな記事を書いてみました！

合格までの道のりは以下の記事とほとんど同じなので、気になった方はぜひ勉強しましょう！！

https://qiita.com/Shibuya_K/items/f69d55257823eb6ff72a
指定期間の日の出、日の入データをPythonのastralライブラリを使用して取得する

以下にコードを添付します。
実行前にastralライブラリをインストールしてください。

下記のページと比較することでデータに差異がないか確認できます。
###### 国立天文台 日の出入り
https://eco.mtk.nao.ac.jp/koyomi/dni/2017/s2401.html

``` python:日の入り時刻.py
from astral import LocationInfo
from astral.sun import sun
from datetime import datetime, timedelta, timezone

def get_sunrise_sunset(lat, lon, start_date, end_date):
    location = LocationInfo(latitude=lat, longitude=lon)
    current_date = start_date
    sun_times = []
    
    while current_date <= end_date:
        s = sun(location.observer, date=current_date)
        # 時間の形式を変更と日本標準時に変更
        jst = timezone(timedelta(hours=9))
        sunrise = s['sunrise'].astimezone(jst).strftime('%Y-%m-%d %H:%M:%S')
        sunset = s['sunset'].astimezone(jst).strftime('%Y-%m-%d %H:%M:%S')
        sun_times.append((current_date, sunrise, sunset))
        current_date += timedelta(days=1)
    
    return sun_times

# 名古屋市の緯度経度を指定
latitude = 35.1667
longitude = 136.9167

# 開始日と終了日を指定
start_date = datetime(2017, 1, 1)
end_date = datetime(2017, 1, 31)

sun_times = get_sunrise_sunset(latitude, longitude, start_date, end_date)

for date, sunrise, sunset in sun_times:
    print(f"日付: {date.date()}, 日の出: {sunrise}, 日の入り: {sunset}")
```
JavaScriptな世界に少しTypeScriptの恩恵をもたらす

## はじめに

様々な議論・理由により、TypeScriptではなくJavaScriptでプロダクトを開発するという事はあると思う。ただ、VS Codeで開発をしている場合、TypeScriptであればinterfaceなどを定義していることで、プロパティやメソッドが補完されるというメリットを享受できるが、JavaScriptであれば補完のメリットは受けられない。

例えば、以下はexpress.jsの`app.locals`に任意のプロパティを追加しているが、それが補完されない例。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/e20e342d-4379-f734-73f9-b852fdf2828d.png)

そこで今回はJSDocと`xxx.d.ts`、jsconfig.jsonを利用して、VS Codeに対して変数の型を伝えるという事を行い、補完が機能するようにしてみたいと思う。

:::note info
TypeScriptなどの静的型付け言語を利用するのは、コンパイル時（実行前）にエラーを発見できるというメリットがあり、今回取り上げる補完は付随的なメリットでしかないかもしれません。ただ、その付随的なメリットである補完さえも受けられないJavaScriptで補完されるようになることは少なからずメリットになるというスタンスです。
:::

## 結論

以下のようなファイルと作成する。

```json:jsconfig.json
{
	"include": ["src/**/*.js", "src/**/*.d.ts"]
}
```
```ts:src/types/express.d.ts
import { Model, ModelStatic, Sequelize } from 'sequelize';
import CustomError from '../lib/custom-error';

declare global {
	namespace Express {
		interface Locals {
			sequelize: Sequelize;
			models: {
				comment: ModelStatic<Model>;
				like: ModelStatic<Model>;
				post: ModelStatic<Model>;
				user: ModelStatic<Model>;
				vLike: ModelStatic<Model>;
			};
			CustomError: CustomError;
		}
	}
}
```
```js:src/index.js
// 省略

/** @type {import("express").Application} */
const app = express();

// 省略
```

すると、以下のように型情報がVS Codeに伝わるため、補完が効くようになりJavaScriptで開発する際にもインターフェースやプロパティを参照して、開発の生産性と品質の向上に役立てられる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/0f70a829-185f-8521-5822-61c6cfdd6988.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/0b352218-411c-d3db-ef59-27733ae3bd99.png)

## まとめ

今回はJavaScriptの世界で、JSDocと`xx.d.ts`、jsconfig.jsonによって型情報をVS Codeに伝えることで、補完が効くようにする方法を試してみた。

ちなみに、今回やってみた方法は実はSvelteなどのOSSでも採用されている方法で、SvelteはJavaScriptで実装されているが、JSDocで型を定義するという方式になっており、今回やってみたJSDocでの型定義は奇抜な方法ではない（と思っている）。

## 参考

- [TypeScript vs JSDoc という対立は存在しない、と思った話](https://qiita.com/fsd-tetsu/items/d8b50481b6c735ffa6f3)
- [You might not need TypeScript... (syntax)](https://jimmywarting.github.io/you-might-not-need-typescript/)
【正規表現】htmlタグの書き換え


例えば下記のh2タグをh1に書き換えたい時

```
<h2 class="blog-ttl">タイトル</h2>
```

検索値はこれ
```
<h2 class="blog-ttl">(.*)</h2>
```
置換値はこれ
```
<h1 class="blog-ttl">$1</h1>
```

するとこうなる

```
<h1 class="blog-ttl">タイトル</h1>
```