OmniAICreator/Qiita-1.07M huggingface dataset:
mysql起動時に起こったERROR! The server quit without updating PID file (/usr/local/var/mysql/MacBook-Pro.local.pid).を解決したときにやったこと。


Mysqlをインストールして、起動した時に発生したエラーを解消するために行ったことを掲載します

下記の記事を参考に解決を試みてダメだった方の参考になればと思います。
https://qiita.com/YSWEngineer/items/29931e549a421a4b204c
https://qiita.com/sxkxsho/items/723dcac7c856d7ddab40
https://qiita.com/jonakp/items/477a18d4a94c01a31583

### 対象となる方
#### mysql インストール時に下記のwarning が出た方。
Warning: The post-install step did not complete successfully
You can try again using:
  brew postinstall mysql
#### その後のmysql.server start　コマンド実行でエラーが出た方
 % mysql.server start
Starting MySQL
./usr/local/Cellar/mysql/9.0.1_9/bin/mysqld_safe: line 144: /usr/local/var/mysql/MacBook-Pro.local.err: Permission denied
/usr/local/Cellar/mysql/9.0.1_9/bin/mysqld_safe: line 144: /usr/local/var/mysql/MacBook-Pro.local.err: Permission denied
/usr/local/Cellar/mysql/9.0.1_9/bin/mysqld_safe: line 199: /usr/local/var/mysql/MacBook-Pro.local.err: Permission denied
/usr/local/Cellar/mysql/9.0.1_9/bin/mysqld_safe: line 144: /usr/local/var/mysql/MacBook-Pro.local.err: Permission denied
 ERROR! The server quit without updating PID file (/usr/local/var/mysql/MacBook-Pro.local.pid).



##### 使用OS :macOS Sonoma version 14.6.1

##### インストールしたMysql :
mysql --version
mysql  Ver 9.0.1 for macos14.7 on x86_64 (Homebrew)

## 結論：過去にインストールしたmysqlが原因でした。
エンジニア転職時に研修でインストールしたmysqlを一度アンインストールして最新のmysqlをインストールしていたのですが、どうやら過去に使用したmysqlのゴミファイルが残っていたようです。


## 解決までに行ったこと

#### warning 発生時にYou can try again using:brew postinstall mysqlと言われたのでとりあえずコマンド実行→エラー発生

2024-12-31T09:58:42.015131Z 0 [System] [MY-015017] [Server] MySQL Server Initialization - start.
2024-12-31T09:58:42.030385Z 0 [System] [MY-013169] [Server] /usr/local/Cellar/mysql/9.0.1_9/bin/mysqld (mysqld 9.0.1) initializing of server in progress as process 8370
2024-12-31T09:58:42.044566Z 0 [ERROR] [MY-010457] [Server] --initialize specified but the data directory has files in it. Aborting.
2024-12-31T09:58:42.044589Z 0 [ERROR] [MY-013236] [Server] The designated data directory <font color="red">/usr/local/var/mysql/ is unusable. You can remove all files that the server added to it. </font>

2024-12-31T09:58:42.044687Z 0 [ERROR] [MY-010119] [Server] Aborting
2024-12-31T09:58:42.052260Z 0 [System] [MY-015018] [Server] MySQL Server Initialization - end.

#### 赤字部分のファイルを確認したところ他のmysql関連のフォルダとは変更日が違うことを確認
＊ここ数日このエラーで悩まされていたので変更日が一昨日担ってますが、実際は過去に使用したmysqlの残骸でした
＊事後なのですでにリネームしてますが元々はmysqlというファイル名でした

 % cd usr
 % open local

![スクリーンショット 2024-12-31 午後7.36.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910978/16d903c8-80f1-1fdf-9010-20a3fcb63dcb.png)


![スクリーンショット 2024-12-31 午後7.35.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3910978/26b2a0d3-7b68-9e9e-cb2d-7ad1cf7074aa.png)

#### ファイル名を mysql → _mysqlに変更して、再度　brew  postinstall musqlを実行
 % brew postinstall mysql
==> Postinstalling mysql
==> /usr/local/Cellar/mysql/9.0.1_9/bin/mysqld --initialize-insecure --user=******* --basedir=/usr/local/C

#### mysql.server startで起動
Starting MySQL
 SUCCESS! 


 無事mysqlの起動がかくにんできました！このエラー解決に3日使ってしまった、、、
 過去に一度mysqlをインストールしたことがある方は同じような
 エラーが考えられますので、よかったら参考にしてください。
【PowerApps】With関数の使い方

## 動画でも解説しました

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

## With関数とは
公式サイトの説明を読んでも、正直よく分かりません。
私は「ForAll関数内や非動作プロパティ内でも、変数を作成して計算できる関数」として理解しています。

ForAll関数内では、Set関数やUpdateContext関数が使えません。
また、Textプロパティなどの非動作プロパティ内でも変数が使えません。
With関数はそういった関数やプロパティ内でも、変数を使用したいときに重宝する関数です。

## 記述方法
With関数の記述方法はこちら
```java
With({変数名:数式},変数を使用した計算式)
```
↑第1引数に波括弧{}で変数を設定して、第2引数で変数を使用した計算式を記述します。
```java
With({X:1},X+2)
```
↑こちらは記述例ですが、Textプロパティに記述すると、結果の３が表示されます。

```java
With({X:1,Y:3,Z:5},X+Y+Z)
```
↑このように「,」区切りで複数の変数を設定することができます。

はじめはどう記述したら良いか迷います。
とりあえず「波括弧で変数を設定」と覚えましょう。

## 使いどころ１ 非動作プロパティ内
With関数の便利なところは、数式で繰り返し同じような記述をしなければならないときに便利です。

```java
If(Checkbox1_1.Value,
    Distinct(
        Table(
            ForAll(Filter(test_list1,user_mail=Dropdown1_1.SelectedText.Value),user_mail),
            ForAll(Filter(test_list1,user_mail=Dropdown1_1.SelectedText.Value),user_name),
            ForAll(Filter(test_list1,user_mail=Dropdown1_1.SelectedText.Value),memo)
        ),
        Value
    )
    ,
    Table(
        ForAll(Filter(test_list1,user_mail=Dropdown1_1.SelectedText.Value),user_mail),
        ForAll(Filter(test_list1,user_mail=Dropdown1_1.SelectedText.Value),user_name),
        ForAll(Filter(test_list1,user_mail=Dropdown1_1.SelectedText.Value),memo)
    )
)
```
↑このように何度もFilter関数で記述しているコードでも

```java
With({
    col_list:Filter(test_list1,user_mail=Dropdown1_1.SelectedText.Value)
    },
    With({
        col_table:
        Table(
            ForAll(col_list,user_mail),
            ForAll(col_list,user_name),
            ForAll(col_list,memo)
        )
    },
        If(Checkbox1_1.Value,
            Distinct(col_table,Value),
            col_table
        )
    )
)
```
With関数を使うことで、Filter関数は1か所で済みます。
ForAll関数についても半分に抑えられていますね。

## 使いどころ２ ForAll関数内
ForAll関数内の繰り返し処理の中で使用する機会が結構あります。
たとえば、リストが２つあって、リストからコレクションを作成する際に、LookUp関数などで該当する値をもう１つのリストから追加する際にうまく追加できない場合があります。

```java
Clear(col_maillist);
ForAll(test_list2,
    Collect(col_maillist,
        {
            mail:user_mail,
            user:user_name,
            app_id:LookUp(appID,user_mail=user_mail).app_id
        }
    )
)
```
このように書いてメールアドレスで検索してapp_idをコレクションに追加するコードを書いたとします。
問題となるのは```app_id:LookUp(appID,user_mail=user_mail).app_id```この部分で、app_idは[[エラー]]になってしまいます。ThisRecord.user_mailと書いてもうまくいきませんでした。

そういう時に
```java
Clear(col_maillist);
ForAll(test_list2,
    With({_mailad:user_mail},
        Collect(col_maillist,
            {
                mail:user_mail,
                user:user_name,
                app_id:LookUp(appID,user_mail=_mailad).app_id
            }
        )
    )
)
```
このようにWith関数で変数を設定することで、列名の競合を回避することができます。

## With関数を使用するメリット
ForAll関数内や非動作プロパティ内で使用できるのが最大のメリットですが、
コードが綺麗にまとまることや、繰り返し処理が減ることで処理速度の向上にもつながります。
実際に、With関数無しと有りで比べたところ、1秒近く差が出ました。
Flutter と Riverpod で ChatGPT クライアントを作ってみた話 ～LINE 風チャット UI 編～

# Flutter と Riverpod で ChatGPT クライアントを作ってみた話 ～LINE 風チャット UI 編～

こんにちは。  
今回は、私が開発した「Flutter × Riverpod で構築した ChatGPT クライアントアプリケーション」についてご紹介します。LINE のチャット画面を思わせるようなデザインを採用しており、OpenAI が提供する ChatGPT API（GPT-4 ベース）と連携してリアルタイムの双方向チャットを実現しています。

## どんなアプリなの？

- **LINE 風のチャット UI**  
  見慣れたメッセンジャーアプリのようなシンプルでわかりやすいインターフェースを採用しています。  
- **ChatGPT とのリアルタイムチャット**  
  OpenAI の GPT-4 をベースとしたモデルを使うことで、会話の文脈を把握して応答してくれます。何気ない雑談から少し突っ込んだ内容まで、まるで人間とチャットしているかのような体験が可能です。  
- **Riverpod による状態管理**  
  ビジネスロジックと UI を分離しやすい構造を採用しており、今後の機能追加や保守がしやすいアプリケーションに仕上げています。  
- **レスポンシブデザイン**  
  スマートフォンからタブレット、Web など、さまざまな画面サイズにも対応できるように工夫しています。

---

## 開発の背景

「ChatGPT を自分好みの UI で使えたらいいな」と思ったのがきっかけでした。特に、普段 LINE やその他のチャットツールを使っているので、同じ感覚で GPT と会話ができれば便利だと考えています。  
Flutter はマルチプラットフォームに対応しており、1 つのコードベースで iOS、Android、Web などにビルドできます。加えて、Riverpod は状態管理がとてもシンプルに書けるため採用しました。

---

## 実装スクリーンショット

下のスクリーンショットのように、吹き出しベースのチャットデザインです。  
簡素な見た目ですが、直感的に操作できるよう工夫しています。

![flutter-chatgpt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125746/2fca9433-67cb-d832-bfc8-f50d0f9160a9.png)

---

## 使用技術

- [**Flutter**](https://flutter.dev/) … クロスプラットフォーム開発
- [**Riverpod**](https://riverpod.dev/) … アプリの状態管理
- [**OpenAI API**](https://platform.openai.com/) … GPT-4 (ChatGPT) の API
- [**Freezed**](https://pub.dev/packages/freezed) … データクラス生成やコード生成に利用
- [**flutter_dotenv**](https://pub.dev/packages/flutter_dotenv) … 環境変数管理

今回のアプリは、以下のバージョンで開発しています。  

- Flutter 3.19.x 以上  
- Dart 3.3.x 以上  

---

## セットアップ手順

もし興味がありましたら、以下の手順で試してみてください。  

1. **リポジトリをクローン**  
   ```bash
   git clone https://github.com/softjapan/flutter_chatgpt.git
   ```
2. **依存関係のインストール**  
   ```bash
   flutter pub get
   ```
3. **環境変数の設定**  
   プロジェクトのルートディレクトリに `.env` ファイルを作成して、次のように設定します。
   ```
   endpoint='https://api.openai.com/v1/'
   model='gpt-4-turbo-preview'
   aiToken='your-api-key-here'
   ```
   ※ ここに書いている API キーは、ご自身の OpenAI アカウントで発行したものに差し替えてください。  
4. **アプリケーションの実行**  
   ```bash
   flutter run
   ```  
   これでアプリが起動します。お手持ちのデバイスやエミュレーター、または Web ブラウザからアクセスしてみてください。

---

## リポジトリ

プロジェクトの詳細やソースコードは GitHub にて公開しています。興味がある方はぜひご覧ください。

[Flutter ChatGPT リポジトリ](https://github.com/softjapan/flutter_chatgpt)

---

## 今後の展望

- **UI のカスタマイズ**  
  より一層LINEに近い見た目にする、ダークモードへの対応など、UI の拡張を検討しています。  
- **複数モデル対応**  
  GPT-4 だけでなく、速度重視で GPT-3.5 を切り替えられるようにするなど、柔軟なモデル選択機能を追加予定です。  
- **ログイン/ユーザ管理機能**  
  複数ユーザーがそれぞれのアカウントで GPT にアクセスできるようにすると便利そうなので、そのあたりも視野に入れています。  

---

## 最後に

LINE 風の UI で気軽に ChatGPT とおしゃべりできるアプリを作りたい、という思いから始めたこのプロジェクトですが、Flutter と Riverpod のシンプルさも相まって非常に開発しやすかった印象です。  
今後も追加機能やデザインの改良など、随時アップデートしていく予定です。もしよかったら、このプロジェクトをチェックしていただけると嬉しいです。

また、何かご意見やアドバイスなどあれば、気軽にコメントや Issue を立てていただけると助かります。  

それではまた、次回の記事で！  

---

**この記事の筆者 (開発者)**  
[FullStack@ITエンジニア（Twitter）](https://twitter.com/softbasejp)

GitHub: [softjapan/flutter_chatgpt](https://github.com/softjapan/flutter_chatgpt)
paiza 勉強記録【文字列の抽出】【Java】

paizaでの勉強記録です。
今回は下記のレベルアップ問題集のCランク問題の「文字列の抽出」を実施しました。
区切り文字で区切られた文字が空文字の場合の処理で、処理済みの文字の場所を示すiの値を更新する処理を入れ忘れてしまい、一度空文字がでた後永遠に同じ場所を見続けて標準出力で＜blank＞を吐き続けるようになりエラーになってしまってました、、、

```java
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

//        区切り文字の開始の文字
        String startSeparator = sc.next();
//        区切り文字の終了の文字
        String endSeparator = sc.next();
//        標準入力で受け取った処理対象文字列
        String inputString = sc.next();
//        処理対象文字列内の区切り文字で区切られた文字列
        String targetString;
        
//        区切り文字の総文字数
        int tagCharCount = startSeparator.length() + endSeparator.length();
//        未処理の文字列の文字数用変数
//        ループ処理の初期条件用に最初は取得文字列を代入する
        int remainCharCount = inputString.length();
//        処理が終了した区切り文字の次の区切り文字の位置を取得するための変数
        int i = 0;
        
        while (true) {
//        	未処理の文字列の文字数が区切り文字の総文字数以上の場合処理を継続する
//        	以下の場合、ループ処理を抜ける
        	if (remainCharCount>=tagCharCount) {
//        		区切り文字の位置を取得
        		int startSeparatorIndex = inputString.indexOf(startSeparator,i);
        		int endSeparatorIndex = inputString.indexOf(endSeparator,i);
        		
//        		未処理の文字数の取得
        		remainCharCount = inputString.length() - (endSeparatorIndex + endSeparator.length());
        		
//        		残りの文字列に区切り文字がある場合、処理を継続する
//        		ない場合、ループ処理を抜ける
        		if (startSeparatorIndex != -1) {
        			targetString = inputString.substring(startSeparatorIndex+startSeparator.length(), endSeparatorIndex);
        			
//        			区切り文字で区切られた文字列が空文字かを判定する
        			if (targetString.equals("")) {
        				System.out.println("<blank>");
        				i = endSeparatorIndex+endSeparator.length();
        			} else {
        				System.out.println(targetString);
        				i = endSeparatorIndex+endSeparator.length();
        			}
				} else {
					break;
				}
			} else {
				break;
			}
		}
        
        sc.close();
    }
}
```

### 参考

https://www.sejuku.net/blog/20546

https://shiken-kouryaku-joho.com/javaindexofhukusuu/
Pygameを使って RPGを作る（5. 衝突判定）

# 概要
本記事はキャラクターとブロックの衝突判定を行う

# 使い方の例
colliderect()
rect1とrect2の衝突判定
rect1.colliderect(rect2) -> bool

# Block準備
衝突用Blockクラスを用意する
```py
class Block:
    def __init__(self, pos, id):
        # イメージの読み込み
        self.surface = pg.image.load(BLOCK_PATH).convert()
        # 位置
        self.pos = pos
        # rect
        self.rect = self.surface.get_frect(center=pos)
        # 識別用id
        self.id = id
```

衝突判定メソッドの実装(Blockクラスに実装）
```py
def collision(self, target_rect):
    if self.rect.colliderect(target_rect):
        print(f'Block ID:{self.id}とplayerと衝突しました。')
```
main.py
```py
import pygame as pg
from settings import *

from player import Player
from wall import Block

class game:
    def __init__(self):
        pg.init()

        # screen
        self.display_surface = pg.display.set_mode((WIDTH, HEIGHT))
        # title
        pg.display.set_caption(TITLE)
        # clock
        self.clock = pg.time.Clock()
        self.running = True

        # Playerクラスのインスタンス宣言
        self.player = Player([250,100])

        # Blockリスト
        self.block_list = []
        for i in range(1,5):
            self.block = Block((i * 200, 100),i)
            self.block_list.append(self.block)

    def run(self):
        """ゲームループ"""
        dt = self.clock.tick(FPS) / 1000

        while self.running:
            # イベント処理
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    self.running = False

            # draw
            self.display_surface.fill(BLUE)

            # 衝突用ブロック
            for block in self.block_list:
                self.display_surface.blit(block.surface, block.rect)
                block.collision(self.player.rect)
            # playerの表示    
            self.display_surface.blit(self.player.surface,self.player.rect)

            # キーボードイベントリスナー
            self.player.input_with_rect(dt)
            
            pg.display.update()

        pg.quit()

if __name__ == "__main__":
    new_game = game()
    new_game.run()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/d1f106c9-b348-8c02-283d-79ce1c650d54.png)

```terminal
Block ID:2とplayerと衝突しました。
```
上記の実装だとBlockとの衝突判定はできるが、その後にPlayerの移動制限をかけたいので、主体性はPlayerクラスが持っているので、衝突判定をPlayerクラスで実装した場合は以下となる。
```py 
def collision(self, block_list):
    for block in block_list:
        if block.rect.colliderect(self.rect):
            print(f'Block ID:{block.id}とplayerと衝突しました。')
```
メインクラスは
```py
# 衝突判定
self.player.collision(self.block_list)
```
C++の可変長配列、幻の `std::dynarray` に関するメモ

`std::vector` よりも機能を削って軽量・高速にした動的配列 `std::dynarray` なるものが、過去のC++規格ドラフトにて提案されたことがあります。
いわば、`std::arrray` の要素数をコンパイル時でなく実行時に指定できるようにしたものです。

C++14で追加されるという話は存在したものの結局は見送られ、今現在もなお使用できるようなる気配はありません。

以下にこの `std::dynarray` の提案理由や技術周辺をざっと調べた結果をメモしておきます。踏み込んだ話題には乏しく、間違いも多々含まれる可能性があるためご了承ください。

## 概要 ―`std::dynarray`とは―

C++を書いていて、実行時に初めて得られる値を長さとした、簡単な配列が欲しいときどうしましょう。色々思いつきますが、

- `malloc()` …C言語は半端に混ぜたくない
- `new` …スマートポインタ等整備されてきたモダンC++では気が引ける
- `std::make_unique<>()` …適しているが、配列ならば専用のクラスを使いたくなる
- `std::array` …良い機能。しかしコンパイル時に長さが決まらないと使えない
- `std::vector` …これが正解

。。。本当でしょうか？

確かにどんな場面でも、原則`vector`を使えば間違いはないです。しかし、本当に短時間だけ確保できればよく、後々のサイズ変更も必要ないという状況もあります。例えば以下はOpenGLのエラーメッセージをchar(GLchar)の配列として取得するコードですが、こうしたC言語ベースのライブラリにおける文字列の扱いなどでは頻出のパターンかもしれません。

```C++
// 失敗していたらエラーログの例外を投げる
GLsizei buf_size; // ログメッセージの長さ
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &buf_size);

auto info_log = std::make_unique<GLchar[]>(buf_size); // ログの文字列を格納する領域
glGetShaderInfoLog(shader_id, buf_size, nullptr, info_log.get());

throw GLShaderCreationException(info_log.get()); // エラーログ付きのオリジナルの例外
```

文字数が`buf_size`なので、その長さのメモリ領域が必要です。ここでは`std::make_unique<char[]>(buf_size)`とすることで、charの連続した領域をヒープに確保（&スマートポインタで管理）しています。

これはこれで全く問題なく動作するのですが、`char[]`というある意味原始的な型を直接扱うのではなく、`std::array`や`atd::vector`といった配列専用のクラスを使えるならば使ったほうがより綺麗という考えもあります。（事実、上記のコードはclang-tidyによって *Do not declare C-style arrays, use std::array<> instead (modernize-avoid-c-arrays)* というヒントが発されます）

ヒントに愚直に従って`array`を使おうにも、サイズがコンパイル時に決まらないためどうやっても不可能です。ならばと代わりに`vector`を用いたくなりますが、文字列を受け取って例外へコピーするというだけのために、挿入や削除・サイズ変更に伴って自動でメモリ再確保を行うなどの高機能を備える`vector`を使うのは些かオーバースペックと感じます。[^1]

[^1]: 実際の開発現場においては、ほとんどの場合`vector`による僅かな性能低下など無視すべきだと大前提として抑えておく必要はあります。「時期尚早な最適化は行わない」のを心に留めた上で、いざこれがボトルネックを生じる状況に遭遇した際、どうすればいいのかを考察することに意義があると思います。また、こうした知識に基づいて普段から意識をしていれば、全体的な性能の底上げに繋がる場合もあるでしょう。

そこで登場するのがarrayとvectorの中間に位置する、`std::dynarray`です。
```C++
std::dynarray<int> foo(5); // 長さ5のデフォルト初期化された配列を確保
std::dynarray<int> bar(5, 3); // 初期値3、長さ5の配列を確保
```
のように使います。添字やイテレータによるアクセス・`front()`, `back()`, `data()`などは可能ですが、vectorとは異なり要素数を変更する`insert()`や`erase()`の操作はできません。付随してsizeとcapacityの相違などの概念も存在せず、メモリの再確保に関する機能が削減されていることが分かります。

また最も重要な点として、dynarrayはヒープでなく**スタックにメモリを確保する**という特長があります。
なんと可変長にもかかわらずヒープを使う必要が無いのです。一般論としてオーバーヘッドとなりうるヒープアロケーションを行わないという部分は、スマートポインタやvectorに対して明確に差別化できるポイントです。

# スタック領域を利用した可変長技術

ここまで書いてきたものの、実は動的な固定長を持った配列の実現方法はdynarrayだけではありません。冒頭にも言及しておけばよかったかもしれませんね。

- `alloca()`関数
- GNU拡張もしくはC99以降で使用できるVLA

前者はズバリ、スタック領域にメモリを確保する関数です。後者のVLAは[こちら](https://stackoverflow.com/questions/21182307/how-does-gcc-implement-variable-length-arrays)などで述べられているとおり、関数に制御が移りローカル変数を用意する際に、実行時に指定される回数だけスタックへのプッシュを繰り返すことで実現されているようです。

そもそもスタックに確保するもの（＝ローカル変数）は固定サイズじゃないと駄目じゃないのかと初めは思うかもしれませんが、それはC/C++(Rustとかも)の言語仕様による制限であり、コンピュータの仕組み自体はもう少し柔軟です。現にアセンブリには`pushq` `popq`命令があり、printfなどに代表されるC言語の可変長引数はこれらを駆使して実現されています。

# その他雑記
「動的に定まる固定長」という話題からは少しずれますが、`llvm::SmallVector`や`boost::container::static_vector` & `boost::container::small_vector`も存在するようです（[別の方の解説記事](https://qiita.com/shohirose/items/54d75b12abd452ee2786)）。用途によっては便利でしょう。

`std::valarray`というのもあると後に知りました。しかしcharには使えないのかな？
2024年総括まとめ

## 今年実施した作業
1. PMO、受入試験
2. VBA設計～製造、テスト
3. Javaプロジェクトのシステムテスト

## 今年1年を通して改めてわかったこと
> 既存のプロ計(プロジェクト計画書)を理解し書き始める点やWBSの作成基準や内容
> 仕様理解、ドキュメント理解、全体図の把握、手順書の理解について

### 理解の方法として
① 自身で読み進めて理解する
② 他メンバーと理解できているか確認や共有会を実施する
③ WBSを細かく設定する。不安があれば有識者相当の人や依頼者と相談する。


## 課題管理
ExcelやBacklog, Redmine等で課題解決したものを動作確認してチケットを整理して、チケット管理している資料等があれば、内容を最新化する

## VBAで勉強しておいたほうがいいところ
1. CSVファイルのインポート
```vb:test1.vb
    Dim folderPath As String
    Dim fileName As String
    Dim outputPath As String

    folderPath = ThisWorkbook.Path & "\input\"
    fileName = Dir(folderPath & "*.csv")
    outputPath = ThisWorkbook.Path & "\output\Process_" & Format(Now, "yyyymmdd_hhnss") & "_"
    
```
2. ExcelファイルやCSVファイルのエクスポート
```vb
    Dim newWb As Workbook
    ' 新しいブックを保存
    newWb.SaveAs outputPath & ".xlsx"
```
3. テンプレートシートに沿った転記やエクスポート
```vb
    Dim templateWb As Workbook
    ' テンプレートブックを開く
    Set templateWb = Workbooks.Open(wbPath & "\template.xlsx")
```
4. Copilotとの対話してコードの課題点等を整理する力   

※転記するときは行と列の場所やデータ最後に要注意
```vb
   '(1) データの最終行を取得
    Dim maxRow As Long
    maxRow = Cells(Rows.Count, 1).End(xlUp).Row
    
    '(2) データ範囲を一括で転記
    Range("E3:G" & maxRow).Value = Range("A3:C" & maxRow).Value

    '(3) 以下のように直接番地を入れる方がいい場合もあります
      wb.Sheets(1).Cells(r, c).Value
    ' wb はワークブックオブジェクトを表します。
    ' Sheets(1) はワークブック内の最初のシートを指します。
    ' Cells(r, c) は行 r、列 c のセルを指定します。
    ' .Value はそのセルの値を取得または設定します。

```

## 来年は
Java開発保守にシフトして、依頼に対して設計書修正、コーディング修正や単体確認を
久しぶりに実施するため、チーム内での記載粒度やレビュー粒度を合わせていき、
ソースでいうところの他者とのコンフリクトは起きないようにし、充実したエンジニアとして進んでいきたい。

## 参考URL
報連相とは？できない人の特徴や原因と重要性や本当の意味を解説
https://www.hrbrain.jp/media/human-resources-development/reporting-contacting-consultation

話がわかりやすい人が押さえている「上手に結論から話す」コツ2選
https://studyhacker.net/conclusion-first_

【口下手でもできる！】人に好かれる雑談力
https://www.youtube.com/watch?v=xYBAgb8oBmc

なぜか好かれちゃう人の共通点
https://www.youtube.com/watch?v=z7ISC6r0fEQ
テストメディアファイル(画像、動画)作成方法

### きっかけ
X, Facebook, Instagramなど画像や動画をアップロードするとき、指定するファイルタイプ、サイズだけアップロードできます。以下のように、Xの仕様となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953086/725d78c7-7f3c-b501-f542-1293e7ade757.png)
SNSのAPIを開発する場合、アップロードする前にメディアファイルのバリデーションをしないといけなくなります。
バリデーションのテストで指定するメディアファイルを作成する必要があります。例えば、5MBの画像ファイル、5.1MBの画像ファイル、4.9MBの画像ファイルなど
### メディアファイルの作成方法
  - 指定する`width`, `height`の画像を作成する場合、以下のサイトで画像が生成できます。
    - https://placehold.jp/
  - それ以外、ffmpegツールで任意的な画像、動画が作成できます。
    - インストール方法は下記となります。
  https://jp.videoproc.com/edit-convert/how-to-download-and-install-ffmpeg.htm#3.%20Linux%E3%81%A7FFmpeg%E3%82%92%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%EF%BC%86%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
    - 下記のコマンドでファイルをリサイズできます。
    ```ffmpeg -i input.avi -vf scale=320:240 output.avi```
   - 指定するファイルサイズを作成する場合
   アイデア：既存ファイルサイズ + 空ファイルサイズ = 指定するファイルサイズ
 例えば、20MBの画像の場合
     - 既存の画像ファイルサイズを確認(placeholdで作成したファイルでもよい)。
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953086/37c028df-3842-0791-a5fe-0d2690896246.png)
     この場合既存の画像ファイルサイズは`65.1kb = 65.1*1024 = 66662.4` byte
     - 作成したいファイルサイズは`20MB = 20*1024*1024 = 20971520` byteなので、空ファイルサイズ = `20971520 - 66662.4 = 20904857.6` byte。
下記のコマンドで空ファイル作成する。`count = 20904857.6/1024 = 20414(四捨五入)`。
     ```dd if=/dev/zero of=20904857.6.dummy bs=1024 count={count}```
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953086/4511eb41-0aa3-7e6f-6d53-8c51ce075723.png)
     - 既存ファイルと上記に生成した空ファイルをくっつければ、作成したいファイルサイズになります。
     ```cat 1922x1922.png 20904857.6.dummy  > 20MB.png```
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3953086/c4b6a87a-9c6e-0707-d52d-2d587fdec4ed.png)
  - 指定する`width`, `height`の動画を作成する場合、ffmpegツールで作成できます。
    - 下記のコマンドで1920x1922.pngファイルから、5秒の1922x1922の動画が生成できます。
```ffmpeg -loop 1 -framerate 30 -i 1920x1922.png -c:v libx264 -t 5 -pix_fmt yuv420p 1920x1922.mp4```
    - 指定するサイズの動画を作成する場合、画像と同じ方法で作成できます。既存動画ファイルサイズ + 空ファイルサイズ = 指定するファイルサイズ
### まとめ
ffmpegで指定する`width`, `height`, `size`, `再生時間`ファイルを作成できるようになります。組み合わせてテスト用のファイル作成は十分だと思います。
DMSを使用したRDSデータのS3ファイル出力 - CDC編

## はじめに

AWS上でRDSのデータを使用して何らかの処理を行う場合、DBに接続して直接操作する方法やファイル出力を行い、出力したファイルに対して処理を行う方法などが考えられるかと思います。
今回は後者のRDSデータのファイル出力（CDC）に焦点を当て、DMS・S3を利用して実装します。
本記事ではRDSからDMSを利用してS3へデータ出力（CDC）を行う際の各種設定手順とエラーポイントについてまとめていきます。

## 前提条件

・コンソール操作で各種リソースを作成
・データベースはMySQLを使用
・RDS、DMSは異なるVPCに配置
・DMSの作成までは以下と同様

https://qiita.com/Haruki-N/items/b7c4555dccd6f5469388

## CDCのための設定

①DBパラメータグループの作成
・エンジンのタイプおよびパラメータグループファミリーをRDSと同じになるよう設定
・タイプは「DB Parameter Group」を選択

②バイナリログの有効化
・①で作成したパラメータグループに対して変更を適用
・binlog_formatの値を「ROW」に設定
・binlog_checksumの値を「NONE」に設定
・binlog_row_imageの値を「FULL」に設定

③パラメータグループの適用
・RDSで使用するパラメータグループを①で作成したものに変更

<font color=red>※自動バックアップの有効化（バックアップ保持期間が1日以上）が必要です。</font>

## 動作確認

①エンドポイント（RDS）の接続テスト
・エンドポイントの接続タブよりテストを作成
・作成したレプリケーションインスタンスを選択したうえでテストの実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/ae4ca98d-f070-c66b-21ab-e3b42cfcd7c6.png)


②エンドポイント（S3）の接続テスト
・エンドポイントの接続タブよりテストを作成
・作成したレプリケーションインスタンスを選択したうえでテストの実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/7392bb2a-e3e0-0f2a-4f82-c44b7102577d.png)


③データベース移行タスクの作成
・作成したレプリケーションインスタンスを選択
・作成したソースデータベースエンドポイントを選択
・作成したターゲットデータベースエンドポイントを選択
・移行タイプは「**移行と複製**」を選択
・CloudWatch ログを有効化
・テーブルマッピングで適切なスキーマ、テーブルを入力
・移行前評価を無効化
・その他の設定はデフォルト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/da78af6c-acb4-dc12-e6d0-92e8d4076c77.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/7e38a5e0-c583-6628-a5be-a97ed9b9a0cb.png)

④RDSへのデータ投入
・以下と同様にLambdaを利用したRDSへのデータ登録を実施

https://qiita.com/Haruki-N/items/5c9086976d9e84047478

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/68b03d3a-c211-3f0f-85bd-634127f30f71.png)

## エラーポイント

・CDCのための設定不備（パラメータグループの設定ミス）

```text:実行結果（CloudWatchログ）
2024-12-31T09:20:03 [SOURCE_CAPTURE  ]E:  Error Code [10002] : MySQL binary Logging must use ROW format [1020418]  (mysql_endpoint_capture.c:433)
```
<font color=red>※その他エラーは下記記載のものと同様のため割愛します。</font>

https://qiita.com/Haruki-N/items/b7c4555dccd6f5469388

## まとめ
DMSを使用したRDSデータのS3ファイル出力（LOAD AND CDC）を実施してみました。
基本的な設定は単純出力と変わりないため設定周りでのミスなどは起こりにくく感じましたが、エラーが起きた際の原因解決が困難な点は変わりないと感じました。
また、作成されたデータ名がタイムスタンプ情報を保持していたため、後のデータ処理で使用する場合に重複データを処理しないよう制御することは可能かと思いました。
2025年の目標

今年は、インターンや就活で自分のことと向き合う時間が多い1年だったと感じました。最終的に自分の働きたい企業に内定をいただけたので、個人的には頑張った1年でもあったかなと思います笑
今年もあと1日なので、来年にやりたいことを箇条書きで書いていこうかなと思います。

## 研究
- 売上予測に関する論文を月に最低５本読む
- 統計手法、時系列分析、深層学習の知識を深める
- 修論を年内に書き終えて余裕を持った年末を過ごせるようにする

来年の最大の目標は修論を完成させることなのでここは絶対達成させます笑

## Web開発
- 開発アルバイト週６時間以上は出勤する
- 開発アルバイトでVueやバックエンドのタスクを積極的に行う
- React, Goの学習を行う
- ReactとGoで誰かの役に立つWebアプリを作成する
- CSの知識を深める
- Qiitaに学んだことをアウトプットする習慣をつける

開発アルバイトではLaravelを使っていて、比較的にフロントエンド業務が多いので来年からはバックエンドやVueやReactなどのフレームやライブラリを使った開発に挑戦したい。また、コードレビューや他のアルバイトの人のサポートも積極的に行い、チームの貢献度を高めていこうと思います。
バイトだけなく、家でも個人開発を行い、ReactやGoを使って何かシステムを開発したいと思います。現時点では、両親が経営している古着屋の役に立つものを開発しようかなと思っています笑
開発アルバイトや個人開発で学んだことはQiitaでアウトプットすることを来年からやってみようと思います。拙い文章ですが、頑張って習慣化させます笑

## 語学
- 2025年の4月までにTOEIC800点を取得する
- TOEIC800点取得後も毎日最低１時間は英語に触れる
- 英会話や留学生と英語を話す機会を増やす

M2までにTOEIC800点を取得する必要があるので、TOEICの点数を上げることを１番の目標としつつ、就職後も英語、特にスピーキングやリスニングが必要になってくるので毎日英語に触れることを意識しようと思います。

## プライベート
- 海外旅行に行く（５カ国くらい）
- 筋トレを週３で行う
- デジタルデトックスを行う
- 本を１週間で１冊は読む
- 早寝早起き（11時に寝て7時に起きる）
- いらないものを買わない、定期的に断捨離する

## 最後に
こんな感じで来年はこれらのことを実現できるように頑張りたいと思います。これから目標が増えることもあると思うので、随時書き加えていこうと思います。
Pygameを使って RPGを作る（4.Rect）

# 概要
Rectは四角形であるが、Pygameでは次のような重要な役割がある
1. Surfaceをさらにスマートに扱うことができる（細かくカスタマイズができる）
1. 衝突判定できる
1. 描くことも可能

# Rect
Rectは以下に示す。
center/topleft/toprightなど、固有の位置が定義されているので、扱いやすい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/fd1eecaa-d54b-99e8-ec37-6ac14d70c575.png)

# RectsとFRectsの違い
特にFRectsは扱いやすいので、Rectsは使う必要がほとんどない。
※公式のDocを見るとなんとget_frectの記述はありませんでした。

扱い方
```py
# player.py

# イメージの読み込み
self.surface = pg.image.load(IMAGE_PATH).convert_alpha()
# rect
self.rect = self.surface.get_frect(center=pos)

# main.py

# playerの表示    
self.display_surface.blit(self.player.surface,self.player.rect)
```

rectに変更した場合、pos（位置)が使えなくなるため、キャラクターを動かすことができなくなる。
rectそのものがメインとPlayerクラスのインターフェースになるため、
inputメソッドの以下のように変更する
```py
def input_with_rect(self, dt):
    # print(f'pos:{self.pos}')
    # キーボード押されているかをキャッチしてくれる（キーボードイベントリスナー）
    keys = pg.key.get_pressed()
    if keys[pg.K_LEFT]:
        print('左矢印が押されました')
        self.rect.x -= 1 * dt * self.key_speed
    elif keys[pg.K_RIGHT]:
        print('右矢印が押されました')
        self.rect.x += 1 * dt * self.key_speed
    elif keys[pg.K_DOWN]:
        print('↓矢印が押されました')
        self.rect.y += 1 * dt * self.key_speed
    elif keys[pg.K_UP]:
        print('↑矢印が押されました')
        self.rect.y -= 1 * dt * self.key_speed
```
元々のpos[0]→rect.x; pos[1]->rect.yのようにできるので、わかりやすい。

また、rectを使う事で、拡大縮小、回転、マスクなどいろんなことに使えるようになる。

# まとめ
Rectを定義すると、下記のように実装になる
self.display_surface.blit(self.player.surface,self.player.rect)

rectはプロパティが多いので、カスタマイズはやりやすくなる（細かい計算しなくても済む）

<b> pygameでRectとSurfaceはゲーム構成要素として、どのクラスでも扱うぐらい大事なポイント</b>
Django バックエンド開発時によく使った  Azure SQL Database コマンド一覧


- バージョン確認

    ```sql
    SELECT @@VERSION AS SQLServerVersion;
    ```

- カレントデータベース名を取得

    ```sql
    SELECT DB_NAME() AS CurrentDatabase;
    ```

- スキーマの作成

    ```sql
    CREATE SCHEMA dev;
    ```

- スキーマ一覧を取得

    ```sql
    SELECT name AS SchemaName
    FROM sys.schemas;
    ```

- カレントスキーマ名を取得

    ```sql
    SELECT SCHEMA_NAME() AS CurrentSchema;
    ```

- カレントユーザー名を取得

    ```sql
    SELECT SUSER_NAME() AS CurrentLogin;
    ```

- ユーザーの一覧を取得

    ```sql
    SELECT name, type_desc, create_date, modify_date
    FROM sys.database_principals
    ORDER BY name;
    ```

- SQL 認証用のユーザーアカウントを作成

    ```sql
    CREATE LOGIN <your-login-name>
    WITH PASSWORD = '<password>';

    CREATE USER <your-user-name>
    FOR LOGIN <your-login-name>;
    ```

- ユーザーのデフォルトスキーマを変更

    ```sql
    ALTER USER [<your-user-name>] WITH DEFAULT_SCHEMA = dev;
    ```

- 任意のユーザーにロールを付与

    ```sql
    GRANT SELECT, INSERT, UPDATE, DELETE, ALTER ON SCHEMA::dev TO <your-user-name>;
    ```

- 任意のユーザーに付与したロールを削除

    ```sql
    REVOKE INSERT, UPDATE, DELETE, SELECT, ALTER ON SCHEMA::dev FROM [<your-user-name>];
    ```

- 任意のユーザーに DDL 実行権限を付与

    ```sql
    ALTER ROLE db_ddladmin ADD MEMBER [<your-user-name>];
    ```

- ユーザーのロール一覧を取得

    ```sql
    SELECT
        dp.name AS UserName,
        dp.type_desc AS UserType,
        dr.permission_name AS PermissionName,
        dr.state_desc AS PermissionState
    FROM sys.database_principals dp
    LEFT JOIN sys.database_permissions dr ON dp.principal_id = dr.grantee_principal_id
    WHERE dp.name = '<your-user-name>';

    ```
git addした際のLF will be replaced by CRLFについて

git addすると以下のようなメッセージが出ることがある。
毎度調べていて、時間の無駄なのでちゃんと理解しようと思った。

```
git add .
warning: LF will be replaced by CRLF in mysql/auto.cnf.
The file will have its original line endings in your working directory
```

# 原因
gitには改行コードを統一するために、自動で改行コードを変換してくれる機能がある。
CRLF → LF
にcommitしたとき、チェックアウトしたときに変換してくれる。
gitでは改行コードはLFで管理するという方針になっているため。

# 改行コード
そもそも何故こんなことになっているかというと、OSごとに改行の表現が違うから。
LinuxとかmacOSは改行をLFで表す。
windowsはCRLFで表す。
これがごちゃ混ぜになっていると正しく表示されないなどのトラブルにつながるので統一したい。

# 対策
今回の警告は主にwindowsで起きるはず。
放置しても問題はないが、以下の設定をfalseにすることで自動変換を防げる。
```
git config --global core.autoCRLF false
```


# オマケ：chatgptに聞いてみた結果。
```text
 LF will be replaced by CRLF 警告について
原因: この警告は、Gitがファイルの行末文字を変換しようとしているために発生します。これはWindows環境でよく見られます。Gitはデフォルトで、リポジトリ内ではLF（Line Feed）を使用し、チェックアウト時にCRLF（Carriage Return + Line Feed）に変換します。
解決方法:
警告を無視しても問題ありませんが、行末文字の変換を避けたい場合、次のコマンドで変換を無効化できます：
bash
コードをコピーする
git config core.autocrlf false
すでに変換されたファイルを修正する場合は、次のコマンドを実行します：
bash
コードをコピーする
git rm --cached -r .
git reset --hard
```
GitHub Copilot Freeにログイン失敗したとき→全部ログアウト後に再ログイン

# 概要

先日にからサービス提供されたGitHub Copilot Free[^githubcopilotfree]を利用しようとして少々つまずいたので、解消方法をメモ。

結論としては、「全部ログアウトしてから、全部ログインを明示的にする」で解消できた。

[^githubcopilotfree]: https://docs.github.com/ja/copilot/managing-copilot/managing-copilot-as-an-individual-subscriber/about-github-copilot-free

# 現象

* VSCodeからGitHub Copilot Freeを利用開始しようとしたら、
「`unable to subscribe user to github copilot free`」と出る
* Copilot Chatに表示されている「Sign in to GitHub.com」をクリックしてもうんともすんとも言わない

## 発生手順

回避できた後からは再現できなかった、ので発生手順。

1. VSCode拡張機能から、GitHub Copilotを選択してインストール
1. GitHub Copilotの状態アイコンで「`unable to subscribe user to github copilot free`」と表示される

この手順は、公式で案内されている「VS CodeでCopilotを利用する手順」[^howtouse-copilotfree-vscode]そのものだが、2ステップ目でエラーする（というか、サインインできない）。

[^howtouse-copilotfree-vscode]: https://docs.github.com/ja/copilot/managing-copilot/managing-copilot-as-an-individual-subscriber/about-github-copilot-free#vs-code

## 環境

* VSCode: Version: 1.96.2 (user setup)
* GitHub Copilot: Version 1.254.0


# 回避方法

1. VSCodeの左下のユーザーアイコン？を選択して、GitHubアカウントからサインアウトする
    * GitHubからサインアウトするとChatからもサインアウトされるはずだが、されなかったら、そちらも明示的にサインアウトする
    * ![スクリーンショット 2024-12-31 18.11.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125588/0c49313f-4fae-9809-a747-f30fdea55537.png)
 
1. 改めて、GitHub Copilot Chatを開くか、Copilotの右下のステータスアイコン、もしくは左下のユーザーアイコン？から「`Sign in to GitHub.com`」か「`Sign in to User Copilot`」ボタンからGitHubへサインインする
    * 今度は動作するはず
1. ブラウザーが開くので、VSCodeへのGitHubアカウントの紐づけを許諾する
    * 「Authorize Visual-Studio-Code」ボタンをクリック
    * ![スクリーンショット 2024-12-31 17.06.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125588/b31b83d2-3630-428a-a558-54745f81e989.png)
1. VSCodeに戻るが、この状態でも未だエラーが出ている
     * エラーメッセージは「`Your Copilot experience is not fully configured`」に代わる
     * この画面から「`Copilot Setting`」ボタンを押すと、GitHub.com（ブラウザー）のCopilot設定ページに飛ばされるが、そこでは「`You are using Copilot for free `」の表示とともに、同じエラーメッセージが表示されるだけで、解決手段はない
         * https://github.com/settings/copilot
     * ![スクリーンショット 2024-12-31 18.23.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125588/1010d85a-05f4-9ddd-5179-cc1f73a85260.png)
1. VSCodeに戻り、Copilotの右下のステータスアイコンか、上部バーのCopilot Chatアイコンから「`Sign in to GitHub Copilot`」（名称、うろ覚え）を選んで、明示的にGitHub Copilotにも再ログインする
1. GitHub.com（ブラウザー）のCopilot設定ページに戻ると、先ほどのエラーメッセージが「`Your Copilot experience is not fully configured`」が消えている
     * https://github.com/settings/copilot
1. VSCodeを再起動する。エラーメッセージが消えて、Copilot Completion（コード上での補完の方）とCopilot Chatの双方がVSCodeで利用可能となる


# 蛇足

GitHubアカウントへのサインインと、GitHub Copilotへのサインインを明示的に別物と捉えて「両方ともサインアウト、そしてサインイン」するってのに気づくのに手間取った。GitHubアカウントへのサインインばかり再試行してたよ。
iOSでOpenCVを使うためにビルドした

iOS(とiOS Simulator)でOpenCVを使いたいと思い、いろいろ試した試行錯誤と成功方法の記録です。2024年10月に取り組んだことなので、雑な記述が多いです。


# 環境
* MacBook Air
* Apple M1
* CMake 3.30.5
* Python 3.13.0
* Xcode 15.4
* macOS Sonoma 14.6.1

# 動いたが目的に合わなかった
## CocoaPodsを使って導入する
OpenCVを使う目的が、特徴量の検出である、ORB、KAZE、AKAZE、SIFTなどを使うことだったので、OpenCVのバージョンが、SIFTの特許が切れてORBなどと同じように使えるようになったv4.4.0以降である方が良かったため、動かすことができたが、採用せずその後も試行錯誤を続けた。
バージョンが4.3.0でも大丈夫である人は最も簡単に利用できると思うので試してみると良いと思う。

https://dev.classmethod.jp/articles/install-opencv-into-ios-app-using-cocoapods/

# 試してダメだったこと
## iOS版のOpenCVパッケージを読み込んで使う
OpenCV側がiOSのためにパッケージを公開していたので、それを試してみた。パッケージはOpenCVのgithubリポジトリの[Releases](https://github.com/opencv/opencv/releases)からダウンロードできる。

このような記事を参考にした。

https://qiita.com/john-rocky/items/0ac8ffcbf9b8f4227fd5

## 「[Building for Apple Platforms](https://github.com/opencv/opencv/blob/4.9.0/platforms/apple/readme.md)」通りに自前でビルド
Cmake、Pythonなどを揃えて実行したが、エラーが起きずにPythonのコードは実行できるが、たくさんのFailedが出てビルドに失敗。

このような記事と公式のインストラクションを参考にした。

https://docs.opencv.org/4.x/d5/da3/tutorial_ios_install.html

https://dev.classmethod.jp/articles/build-opencv2-xcframework-manually/

# 成功した方法
日本語で探していてもどうしようもなかったので、OpenCVの英語のドキュメントを読んだり、英語で検索したりしたが全く解決できなかったので、OpenCVのissuesをみたら自分と同じような問題に直面している人がいて、それに対して以下の記事を紹介していて、それ通りにやったら問題なく動いた。

https://lightbuzz.com/opencv/

## 方法
1. Python、CMakeなどを準備する
2. OpenCVをクローンする
    *  記事内では4.9.0でcheckoutしているが、しなくても問題なくビルドできた
3. OpenCVをビルドする
    * 記事はvisionProで使えるようにターゲットに追加しているが、私はiPhoneでしか使わないので削除して実行した 
```
python3 platforms/apple/build_xcframework.py --out build_all \
--iphoneos_deployment_target 14.0 \
--iphoneos_archs arm64 \
--iphonesimulator_archs arm64,x86_64 \
--build_only_specified_archs True \
--without objc
```

# まとめ
iOSに自前でビルドしたOpenCVを導入して、適切に特徴量検出をすることができた。またXcodeのシミュレーターでも実行を確認できた。
each_pair

# 対応付けさせる
>each_pair {|member, value| ... } -> self
each_pair -> Enumerator
構造体のメンバ名(Symbol)と値の組を引数にブロックを繰り返し実行します。
```rb
irb(main):010:0> Foo = Struct.new(:foo, :bar)
irb(main):011:0> Foo.new('FOO', 'BAR').each_pair {|m, v| p [m,v]}
[:foo, "FOO"]
[:bar, "BAR"]
=> #<struct Foo foo="FOO", bar="BAR">
```

https://docs.ruby-lang.org/ja/latest/method/Struct/i/each_pair.html
Dockerfileで先にGemfileとGemfile.lockだけをコピーするのって何がうれしいの?

# 疑問
以下はRails7.2でRailsプロジェクトを作成した時のデフォルトのDockerfileの内容の一部です。
```dockerfile
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
    bundle exec bootsnap precompile --gemfile

# Copy application code
COPY my_app .
```
この部分、何も考えず自分で作成するとしたら以下のように書きたくなります。
```dockerfile
COPY my_app .
RUN bundle install && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
    bundle exec bootsnap precompile --gemfile
```
なぜこのように段階を踏んで記述するのでしょうか?
今回はその理由調べてまとめました。

# 理由 1: キャッシュの活用によるビルドの高速化
Dockerではコマンド毎にCOPYやRUNコマンド毎にレイヤーとして情報をキャッシュする仕組みがあります。
キャッシュを利用するかどうかの判定はその時点で差分があるかどうかです。
もし私が書きたいように記述したとするとソースファイルの変更があるたびにキャッシュを利用せずに、`bundle install`をやり直すことになり、ビルドにかなりの時間を割くことになります。
しかし、GemfileとGemfile.lockのみをコピーすることでこれらのファイルに変更がない限りビルド時に`bundle install`を行うことになり効率よくビルドすることができるようになります。

# 理由 2: 依存関係とソースコードの分離
依存関係とソースコードを分離することでデバッグがやりやすくなります。
もし私が書きたいように記述するとソースファイルに問題がある場合のエラー時に原因をGemの依存関係に問題があるのか、それともソースコードに問題があるのかといった原因を切り分けることができます。
また、ソースコードに原因があった場合に、ソースコードを修正しただけでも再び`bundle install`を実行することになります。

# 今回のことで学んだこと
- Dockerfileではコマンド毎にその時点でのレイヤーをキャッシュして差分がない場合はキャッシュしているレイヤーを利用してビルドを行う
- Dockerfileで生成したイメージは全てのレイヤーの情報を保持しているためレイヤーが増えるとイメージが大きくなるのでコマンドはまとめる方がいい
2024年のプリザンターへのコントリビュートをまとめてみた

## はじめに
当社で行っているプリザンター本体コードへのコントリビュート、2024年分をまとめてみました。

## 新機能追加
### 2/13 リリース情報(ver.1.4.1.0)
* [画像をLightBoxで表示する機能を追加。](https://pleasanter.org/manual/general.json)

### 3/12 リリース情報(ver.1.4.2.0)
* [TOTP（Time-based One-Time Password）認証機能を追加。](https://pleasanter.org/manual/totp-authentication)

### 6/11 リリース情報(ver.1.4.5.0)
* [ユーザのパスワードを生成する機能を追加。](https://pleasanter.org/manual/user-new)
* [サイト画像をキャッシュする機能を追加。](https://pleasanter.org/manual/outcache-json)

### 9/10 リリース情報(ver.1.4.8.0)
* [サイトトップからの移動を禁止／許可するオプションを追加。](https://pleasanter.org/manual/user-new)
* [通知機能で変更内容をDiffMatchPatchで表示するモードを追加。](https://pleasanter.org/manual/table-management-notification)

### 12/10 リリース情報(ver.1.4.11.0)
* [セッション情報をKey Value Storeに保存する機能を追加。](https://pleasanter.org/manual/kvs)

## まとめ
2024年の新機能追加は7機能でした。この他にもライブラリのバージョンアップやバグ修正なども実施しています。
当社の社内システムでのプリザンターの運用実績からのフィードバック、特にパワーユーザ～シスオペ目線からの「もうちょっとこうならないかな」の部分を、どんどんフィードバックしていく予定です。2025年も新機能追加を予定していますので、ご期待ください。
Mac で Node.js バージョンアップ

# はじめに

毎回手順忘れるので、備忘録として残しておこうと思います。

# 使用するミドルウェア

- Homebrew
- nodebrew
- Node.js
- npm

# Homebrew のインストール

以下URLからインストールコマンドをコピーして、コマンドを叩きます

https://brew.sh/ja/

Press Return/Enter to continue ~~~ という文章が表示されたら、Enterを押して、次に進みます。

Installation successful が表示されたらOKです。

次に Next Steps と記載されている箇所にコマンドが表示されているので、そのコマンドを叩きます

```bash
eval "$(/opt/homebrew/bin/brew shellenv)"
```

バージョンを確認して、バージョンが表示されたらOKです

```bash
brew -v
```

# nodebrew のインストール

以下コマンドを叩きます

```bash
brew install nodebrew
```

バージョンを確認して、バージョンが表示されたらOKです

```bash
nodebrew -v
```

# プロファイルの確認

.zprofile を確認します。

```bash
cat ~/.zprofile
```

以下が表示されていればPATHが通っていることになります

```bash
eval "$(/opt/homebrew/bin/brew shellenv)"
export PATH=$HOME/.nodebrew/current/bin:$PATH
```

もし記載がなければ、PATHを通す必要があるので zsh の場合は zprofile に上記を追加します。

bash の場合は .bash_profile になるかと思います。

# Node.jsのインストール

インストール可能なバージョンを表示します

```bash
nodebrew ls-remote
```

インストールしたいバージョンをインストールします

今回はLTSをインストールしました

```bash
nodebrew install-binary v22.12.0
```

以下コマンドでインストールしたバージョンを確認することができます

任意のバージョンがあるか確認します

```bash
nodebrew list
```

使いたいバージョンを指定します

```bash
nodebrew use v22.12.0
```

最後にバージョンを確認します。上述のコマンドで指定したバージョンが表示されればOKです。

npm のバージョンも勝手に上がってくれます。

```bash
 node -v
```

# 参考文献

https://brew.sh/ja/

https://qiita.com/arimuuuura/items/95e489a835d7bf31a4a5

https://zenn.dev/gdtypk/articles/m1-mac-use-nodebrew-and-node
‎ActionController::Parameters

# 生成される時の初期化を見てみる
```rb
def initialize(parameters = {}, logging_context = {})
      parameters.each_key do |key|
        unless key.is_a?(String) || key.is_a?(Symbol) # ハッシュのキーが文字列またはシンボルでなければ以下の処理を実行する
          raise InvalidParameterKey, "all keys must be Strings or Symbols, got: #{key.class}"
        end
      end

      @parameters = parameters.with_indifferent_access
      @logging_context = logging_context
      @permitted = self.class.permit_all_parameters
    end
```
https://github.com/rails/rails/blob/6df15e25c875e9c1ee39acb0bc161b6c47531331/actionpack/lib/action_controller/metal/strong_parameters.rb#L287C5-L298C1

### `{}`とは　ハッシュ
https://qiita.com/masatom86650860/items/c261a9f4fa17b419f203

### each_key ハッシュのキーを返す
https://qiita.com/masatom86650860/items/8afd875fa21bf3005649

### with_indifferent_access　ハッシュのサブクラス　文字列、シンボルをハッシュのキーとして同じに見なす
```rb
irb(main):006:0> {"black"=>"#000000", "white"=>"#FFFFFF"}.with_indifferent_access
=> {"black"=>"#000000", "white"=>"#FFFFFF"}
```
https://qiita.com/masatom86650860/items/5f3730eeba540b9f2cba

### permit_all_parameters
`true`を指定するとすべてのパラメータはデフォルトによって許可されるだろう。デフォルトでは`false`になっている

>permit_all_parameters - If it’s true, all the parameters will be permitted by default. The default is false.

https://api.rubyonrails.org/classes/ActionController/Parameters.html#:~:text=permit_all_parameters%20%2D%20If%20it%E2%80%99s%20true%2C%20all%20the%20parameters%20will%20be%20permitted%20by%20default.%20The%20default%20is%20false
M5StickC PLUS2の時計表示（忘備録）

## はじめに
先日、M5StackC PLUS2を購入しました。今回は練習のため、時刻と日付を表示する時計を作成してみました。

https://www.switch-science.com/products/9350

## スケッチ
Arduino IDEのライブラリマネージャで「M5StickC PLUS2 by M5Stack」をインストールした後、以下のスケッチをM5StackC PLUS2に書き込み実行しました。

```
#include "M5StickCPlus2.h"
#include "time.h"
#include <WiFi.h>
#include <M5Unified.h>

// wifiの設定
const char* ssid = "********"; //自宅等のWiFiの情報を入力
const char* password = "********"; //自宅等のWiFiの情報を入力

void setup()
{
    // put your setup code here, to run once:
    M5.begin();
    M5.Lcd.setRotation(3);
    M5.Lcd.fillScreen(BLACK);
    
    // connect to WiFi
    Serial.printf("Connecting to %s ", ssid);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }
    Serial.println(" CONNECTED");
    // Set ntp time to local
    configTime(3600L * 9, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");

    // 起動ごとに時刻同期するために同期タイミングを一時的に変更
    auto default_interval = sntp_get_sync_interval(); // ミリ秒単位
    sntp_set_system_time(1, 0);                       // 1秒

    // Set RTC
    struct tm timeInfo;
    if (getLocalTime(&timeInfo))
    {
        M5.Rtc.setDateTime(timeInfo);
    }

    sntp_set_system_time(default_interval * 1000, 0); // 同期タイミングを戻す

    // disconnect WiFi
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
}

void loop()
{
    M5.Lcd.setTextColor(GREEN, BLACK);
    M5.Lcd.setTextSize(1.5);
    M5.Lcd.setCursor(0, 10, 7);
    M5.Lcd.printf("%02d:%02d\n", M5.Rtc.getTime().hours, M5.Rtc.getTime().minutes);

    M5.Lcd.setTextFont(1);
    M5.Lcd.setCursor(210, 10, 1);
    M5.Lcd.printf("%02d\n", M5.Rtc.getTime().seconds);

    M5.Lcd.setTextColor(WHITE, BLACK);
    M5.Lcd.setCursor(25, 100, 1);
    M5.Lcd.printf("Date:%04d.%02d.%02d\n", M5.Rtc.getDate().year, M5.Rtc.getDate().month, M5.Rtc.getDate().date);

    M5.Lcd.setCursor(25, 120, 1);
    M5.Lcd.printf("Battery Level:%3d%%\n", M5.Power.getBatteryLevel());

    delay(500);
}
```

## 時計表示
時刻と秒は緑色、日付とバッテリ残量は白色で表示します。

![20250102_140649.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1729073/c3e9455e-2dbf-fe7b-6938-5a4e6cf98e19.jpeg)

## 参考
スケッチ全般に関して

https://qiita.com/uduki-oh-yeah/items/10864dbb4f39b0430efa

テキストフォントの種類、大きさなどの設定について

https://lang-ship.com/blog/work/m5stack-m5stickc-plus2-1/#toc8
Dockerコンテナに入る４つの方法と特徴

dockerを使って開発環境を構築しようとしていた時に、
dockerのコンテナ内に入ろうとしたところ、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963315/5145861f-908b-2c33-ce87-a4e9921fc338.png)

なぜか入れない...

でもコンテナは正常に起動しているし、問題なさそうなのに、なぜ...？

この時、今までdockerでの開発環境構築時に、先輩から教わったコマンドを
なんとなーく入力して進めてしまっていたことに気がつきました。

というわけで、今回はdockerコンテナに入るコマンドで、
主要っぽい４つの方法を調べてまとめてみました。

## 1.　docker exec

指定したコンテナ内で新しいシェルを開始するためのコマンド

### ✍️ 記述方法

```bash
docker exec -it <コンテナ名またはID> bash
```

### 💡 ポイント

- 新しいシェルを開き、コンテナ内でコマンドを実行できる状態にしてくれる
- 稼働中のコンテナに対してのみ実行できる
- 複数回実行して、複数のシェルを開くことも可能


## 2.　docker compose exec

docker-compose.yml ファイルで管理されるサービスに限定して使用されるコマンド
`docker exec` と同様に、新しいシェルを開始する

### ✍️ 記述方法

```bash
docker compose exec <サービス名> bash
```



### 💡 ポイント

- docker-compose.ymlファイルに記載された、**サービス名**を指定して実行する
（指定するのはコンテナ名でないことに注意！）
- `docker exec` と同様、新しいシェルを開いてコマンドを
実行可能な状態にしてくれる



## 3.　docker attach


stdinなどコンテナの標準入出力に接続するためのコマンド

### ✍️ 記述方法

```bash
docker attach <コンテナ名>
```

### 💡 ポイント

- 実行中のプロセスの標準入出力にアクセスするだけで、**新しいシェルは開かない**
- プロセスが出力するログやエラーメッセージを確認できる
- **コンテナ内でのコマンド実行はできない**
- セッションの切断時には、`Ctrl`+`C`だとコンテナ自体を停止させる可能性が
あるため、`Ctrl`+`P`（一時的にコマンド入力モードにするショートカット）を
実行後に`Ctrl`+`Q`（ターミナルセッションを切断するショートカット）を
実行した方が良い

## 4.　docker start -ai


停止中のコンテナを起動し、そのコンテナの標準入出力に接続するコマンド

### ✍️ 記述方法

```bash
docker start -ai <コンテナ名>
```

### 💡 ポイント

- 停止中のコンテナに対して実行して起動し、その起動時の標準入出力に接続する
- `docker attach`同様、実行後に**新しいシェルを開かない**
- 実行中のプロセスにアクセスするのではなく、
コンテナの開始時から出力を確認できる

## 筆者がやらかしていた凡ミス
それで結局、筆者は何でdockerコンテナ内に入れなかったのか？というと、
私は`docker compose exec`でコンテナ内に入ろうとしていたのですが、
ここでdocker-compose.yml内に記載してある「**サービス名**」ではなく、
dockerの「**コンテナ名**」を指定していたんです。


docker-compose.yml内で定義されていない名前をサービス名として
指定していたんだから、`service 〇〇 is not running`と言われるのも納得ですね。
Flask Blueprintでコードの保守性を上げる



## こんな悩みがありました

* Flaskアプリケーションのコードが長くなりすぎて管理が大変になってきた
* 機能ごとにファイルを分けたい
* より保守性の高いコード構造にしたい

## Blueprintで解決！

Flaskの`Blueprint`は、大規模なアプリケーションを効率的に管理するための強力な機能です。コードを機能ごとに分割し、整理整頓できます。

## 実際のリファクタリング例

### Before: 全てが1つのファイルに

```python
# app.py
from flask import Flask, render_template...
app = Flask(__name__)

@app.route("/")
def index():
    # スタート画面のコード

@app.route("/quiz/<int:question_id>")
def quiz():
    # クイズ画面のコード

@app.route("/result")
def result():
    # 結果画面のコード
```

### After: きれいに整理

```
├─backend
|   ├─controllers
|   |   ├─index.py #def index
|   |   ├─quiz.py #def quiz
|   |   └─result.py #def result
|   ├─data #データベース 今はjsonで管理 将来的にはmodel.pyに移行
|   ├─gpt #OpenAIAPIを呼び出す
|   ├─static
|   │  ├─js
|   │  └─style
|   ├─templates
|   ├─__init__.py
|   └─model.py #将来的にデータベースを管理する
└─run.py
```

## Blueprintの導入手順

1. コントローラーの作成

```python
# controllers/index.py
from flask import Blueprint
index_bp = Blueprint('index', __name__)

@index_bp.route("/")
def index():
    return render_template("index.html")
```

2. アプリケーションの初期化

```python
# __init__.py
def create_app():
    app = Flask(__name__)
    
    # Blueprintの登録
    from controllers.index import index_bp
    app.register_blueprint(index_bp)
    
    return app
```

3. アプリケーションの起動

```python
# run.py
from backend import create_app
app = create_app()

if __name__ == '__main__':
    app.run(debug=True)
```

## Blueprintを使うメリット

### 1. コードの整理整頓
* 機能ごとに別ファイルに分割することで、コードの見通しが良くなる
* メンテナンスがしやすくなり、バグの特定も容易になる

### 2. チーム開発の効率化
* 担当者ごとに別ファイルで作業できるため、並行開発がスムーズ
* コードの衝突リスクを減らす

### 3. 拡張性の向上
* 新機能の追加が容易になり、既存コードへの影響を最小限に抑えられる
* テストがしやすくなり、品質の向上

## まとめ

Blueprintを導入することで、Flaskアプリケーションを整理された状態で管理できるようになりました。今後の機能追加や保守作業も、より効率的に行えるはずです！
Pandas - CSV の強力なデータ処理ツール


# Pandasライブラリ - CSV の強力なデータ処理ツール

## 1．概要

- Pandasは、NumPyをベースに構築されたオープンソースライブラリで、Pythonのための効率的なデータ分析・処理ツールを提供します。
「Pandas」という名前は、計量経済学の用語「Panel Data」（時間と空間の両方の次元を持つデータ）に由来しています。

- Pandasは2008年、AQR Capital Managementで働いていたWes McKinneyによって、金融データを処理する目的で作成されました。
現在では、Pythonのデータサイエンスエコシステムにおいて最も重要なライブラリの一つとなっています。

## 2．特徴

- 多様なデータ形式への対応: CSV、Excel、SQLデータベース、JSON、Parquetなど、追加のライブラリなしで多くのファイル形式の読み書きが可能です。
- 欠損値の処理: 欠損値（NaN）を柔軟に検出・処理するための強力なツールを提供します。
- データの結合: SQLのような直感的で効率的なマージ・結合操作が可能です。
- 時系列データ: リサンプリング、ローリングウィンドウ、頻度変換など、時系列データの処理を強力にサポートします。

## 3．データ構造

### Series
1次元のデータ構造
あらゆるデータ型（整数、浮動小数点、文字列、オブジェクト）を格納可能
カスタマイズ可能なインデックス
例：

```python
s = pd.Series([1, 3, 5, np.nan, 6, 8])
```

### DataFrame

2次元のデータ構造（表形式）
各列は異なるデータ型を持つことが可能
行インデックスと列名を持つ
例：

```python
df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': ['a', 'b', 'c']
})
```

## 4．Pandasの主な利点

### **高性能**

- C言語による最適化された操作
- NumPyによるベクトル化
- メモリ最適化

### **柔軟性**

- 多様なデータ型の処理
- データ構造の容易な変更
- 多くの統計演算のサポート

### **豊富なエコシステム**

- scikit-learnとの優れた統合
- matplotlibによる可視化
- Daskによる大規模データ分析

## 5．CSV処理における利点

### **効率的なインデックス処理**

```python
# 特定のインデックスでCSVを読み込む
df = pd.read_csv('data.csv', index_col='ID')

# インデックスによる高速アクセス
result = df.loc[1000]
```

### **強力なフィルタリング**
```python
# 複数条件によるフィルタリング
filtered_df = df[
    (df['age'] > 25) & 
    (df['salary'] >= 50000)
]
```

### **柔軟なCSV読み込み**

```python
# 多様なオプションでの読み込み
df = pd.read_csv('data.csv',
    skiprows=2,
    na_values=['NA', 'missing'],
    parse_dates=['date_column']
)
```

### **カスタマイズ可能なCSV書き出し**

```python
# カスタマイズされた形式でCSVを出力
df.to_csv('output.csv',
    index=False,
    float_format='%.2f',
    date_format='%Y-%m-%d'
)
```

## 6．速度のベンチマーク比較
### **Rubyとの比較（gem: csv）**

| ファイルサイズ | Pandas | Ruby CSV |
| ---: | ---: |---: |
| 100MB |0.8秒 | 2.3秒 |
| 500MB |3.9秒 | 11.7秒 |
| 1GB | 7.8秒 | 23.5秒 |

### **Rustとの比較**（crate: csv）

| ファイルサイズ | Pandas | Rust CSV |
| ---: | ---: |---: |
| 100MB | 0.8秒 | 0.3秒 |
| 500MB | 3.9秒 | 1.5秒 |
| 1GB | 7.8秒 | 3.1秒 |

## 7．考察：
- PandasはRuby CSVと比べて大幅に高速
- Pandasは速度と機能性のバランスが取れている
- Pandasはすべてのデータをメモリに読み込むため、メモリ使用量が多い
- Rust CSVはPandasの約2.5倍の速度

## 8．次
- Pandasと同様に rust の polars ライブラリ
DBに論理名をつける

# はじめに
DB設計書にはテーブルやカラムの論理名や備考が書かれていると思います。
DBを構築する際に論理名や備考を設定しておくことができます。
使い道があるかどうかは不明ですが、DBから設計書を作成するときには少し役立ちます。

どこの設定するかというと「拡張プロパティ」に設定します。

SSMSではプロパティ画面で設定/確認ができますが、いちいち開くのが面倒なのでクエリで行う方法を紹介します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/3f26b4a5-3958-2e42-3dc1-65a515d1dab9.png" width=80%>

# クエリ
### 登録/更新/削除
```sql
-- 登録：sp_addextendedproperty
-- 更新：sp_updateextendedproperty
-- 削除：sp_dropextendedproperty
EXEC sys.sp_addextendedproperty
-- 設定値の名前
     @name = 'MS_Description'
-- スキーマ/テーブル/カラムの設定の時に必須
   , @level0type = 'SCHEMA'
   , @level0name = '{スキーマの物理名}'
-- テーブル/カラムの設定の時に必須
   , @level1type = 'TABLE'
   , @level1name = '{テーブルの物理名}'
-- カラムの設定の時に必須
   , @level2type = 'COLUMN'
   , @level2name = '{カラムの物理名}'
-- 設定値（削除の時は不要）
   , @value = '設定値'
```

同じカラム（スキーマ/テーブル）に複数のプロパティを設定する場合は「name」の値を変えます。
SSMSで登録する場合は以下のようにします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/1e6737e6-6382-1606-e91f-6cdf91c6a377.png" width=80%>

### 読出
```sql
SELECT * FROM sys.extended_properties
```

| class | class_desc | major_id | minor_id | name | value |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 | OBJECT_OR_COLUMN | 658101385 | 0 | description | 各科目のテスト結果を登録 |
| 1 | OBJECT_OR_COLUMN | 658101385 | 0 | logical_name | 点数マスタ |
| 1 | OBJECT_OR_COLUMN | 658101385 | 1 | MS_Description | 学籍番号 |
| 1 | OBJECT_OR_COLUMN | 658101385 | 2 | MS_Description | 科目 |
| 1 | OBJECT_OR_COLUMN | 658101385 | 3 | MS_Description | 点数 |
| 3 | SCHEMA | 1 | 0 | MS_Description | デフォルトのスキーマ |

システムテーブルと結合する場合は
major_id：「sys.tables」の「object_id」（スキーマの場合は「1」）
minor_id：「sys.columns」の「column_id」（テーブルの場合は「0」）

https://learn.microsoft.com/ja-jp/sql/relational-databases/system-catalog-views/extended-properties-catalog-views-sys-extended-properties?view=sql-server-ver16