OmniAICreator/Qiita-1.07M huggingface dataset:
VLCメディアプレイヤーでrtmpsの再生が行えなくなったので回避した話

# はじめに

タイトルは「回避」であり「改善」ではない。(その2)

先日の以下の記事の事象に遭遇して思い出したことがあったので記事にしてみようと思う。

https://qiita.com/SECUAL_masa/items/25eafebb44908d53c0d6

現在ストリーミングサーバーを扱っており、また映像配信・視聴時の通信は暗号化している。
また映像確認時にはVLCメディアプレイヤー(以下VLC)を利用することもあった。

これまではVLCの「ネットワークストリームを開く」でrtmpsのURL(rtmps://streaming/streamname/xxx)を入力して映像確認していたのだが、とあるタイミングからrtmpsでの視聴が行えなくなっていることに気が付いた。

毎回の確認でrtmpsを指定している訳でもなかったので気が付くのにしばらくかかったが、その時利用していたVLCのバージョンは3.0.18だった。（ダウンロードした時のexeの更新日時が2022年11月30日なので2年前かぁ～)

![20250128_155215_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1236186/56994d9b-fdc9-59c3-c482-b2be36310080.png)

以前は問題なかったのに何でだ？？？と思って、この時もダウングレードを試したのでその結果をまとめる。

# 確認結果

| Ver | 結果 |
|:-----------:|:------------:|
| 3.0.18 | × |
| 3.0.17 | × |
| 3.0.16 | ○ |

上記の通り3.0.16では問題なかった。
3.0.16ではデフォルトだった設定が3.0.17以降では外れたとか、そういうのはあったかもしれないが、この時も時間がなかったのでひとまずダウングレードという方法をとった。
3.0.18以降はバージョンアップを試みていないので改善できているかは未確認となっている。(現状の最新版は3.0.21の模様)

# 最後に

ダウングレードは自己責任で！
超簡単理解：主キー、外部キー、連動処理（cascade）

## 主キー、外部キー、cascadeとは

テーブル同士を関連づけたい時ってありますよね？
外部キーをつけてあげればいいんです（詳しい方法は次の章）。
そしてテーブル同士が関連づいたということは、一方に変更があった時にはもう一方も変更したいですよね。そういう時は外部キーを設定する時に、cascadeで変更と削除の連動処理を設定してあげればOKです。

```sql
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT, -- 主key
    name VARCHAR(255)
);

CREATE TABLE user_profiles (
    id INT PRIMARY KEY AUTO_INCREMENT, -- 主key
    user_id INT UNIQUE, -- 外部key
    bio TEXT,
    FOREIGN KEY (user_id)
        REFERENCES users (id)
        ON DELETE CASCADE -- 連動
        ON UPDATE CASCADE -- 連動
);
```

- 主キー：データのid
- 外部キー：他のテーブルの主キー
- cascade：外部キーでつながったテーブルの連動して変更や削除するための設定

## 外部キーの設定方法

外部キーの簡単な設定方法を自分なりに編み出しました。
図で説明していきますから、今から紹介する図が頭に浮かべばすぐに外部キーをつけられるはずです。

前提知識として、テーブル同士の関係性は３つあります。
- １対１（学生と学生証）
- １対多（ユーザーと投稿）
- 多対多（学生と授業）

**外部キーは子要素となりそうな方につければいいです。**

### １対１

![スクリーンショット 2025-01-28 15.47.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/c49009dc-5b47-f2f8-4bec-968d382fcc8a.png)

「学生」の「学生証」なので、
学生証の方に外部キーを設定してあげればOKです。

コード：
```sql
-- 学生テーブル
CREATE TABLE Student (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(255) NOT NULL
);

-- 学生証テーブル
CREATE TABLE StudentCard (
  id INT AUTO_INCREMENT PRIMARY KEY,
  cardNumber VARCHAR(255) NOT NULL,
  studentId INT UNIQUE, -- 外部key
  FOREIGN KEY (studentId) REFERENCES Student(id) ON DELETE CASCADE
);
```

### １対多

![スクリーンショット 2025-01-28 16.01.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/02e0445f-737e-7a4f-3c21-1ce5bb65789f.png)

「ユーザー」の「投稿」なので、
投稿の方に外部キーをつけてあげればOKです。


コード：
```sql
-- ユーザーテーブル
CREATE TABLE User (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(255) NOT NULL,
  email VARCHAR(255) NOT NULL UNIQUE
);

-- 投稿テーブル
CREATE TABLE Post (
  id INT AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  content TEXT NOT NULL,
  userId INT,
  FOREIGN KEY (userId) REFERENCES User(id) ON DELETE CASCADE
);

```

### 多対多

多対多は少し特別なので注意してください。

![スクリーンショット 2025-01-28 16.06.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/bc5b4a76-4767-31a2-8563-561c2617f206.png)
![スクリーンショット 2025-01-28 16.07.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/11cac59a-77ac-790f-208b-bd5bf0111975.png)

「学生」は複数の「授業」を受けることができますし、
「授業」は複数の「学生」も受け入れることができます。

この場合は中間テーブルを作り、
中間テーブル内で双方を関連づける外部キーを二つ用意して、
主キーを二つの外部キーから作りましょう。

```sql
-- ユーザーテーブル
CREATE TABLE User (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(255) NOT NULL,
  email VARCHAR(255) NOT NULL UNIQUE
);

-- タグテーブル
CREATE TABLE Tag (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(255) NOT NULL UNIQUE
);

-- 中間テーブル（ユーザーとタグの多対多の関係を管理）
CREATE TABLE User_Tag (
  userId INT,
  tagId INT,
  PRIMARY KEY (userId, tagId),
  FOREIGN KEY (userId) REFERENCES User(id) ON DELETE CASCADE,
  FOREIGN KEY (tagId) REFERENCES Tag(id) ON DELETE CASCADE
);

```

## まとめ

- 子要素となりそうな方に外部キーをつければよい
- 多対多の場合は中間テーブルを設けて外部キーを二つ用意すればよい
VS Codeで正規表現の検索をしたときに調べたこと


## 最初の試み

Railsシステムで任意のエラークラスを検索しようとした時、最初に以下のような検索パターンを試みましたが、期待した結果が得られませんでした：

```
class *Error
```

これが機能しなかった理由は、正規表現では`*`単体では「任意の文字列」を表現できないためです。`*`は量指定子（quantifier）であり、直前のパターンの繰り返し回数を指定するものです。

## 正しい正規表現

正しい正規表現パターンは以下になります：

```
class.*Error
```

## 正規表現の解説

この正規表現は以下の要素で構成されています：

1. `class` - リテラルで"class"という文字列にマッチ
2. `.` - 改行を除く任意の1文字にマッチ
3. `*` - 直前のパターン（この場合は`.`）が0回以上繰り返されることを示す量指定子
4. `Error` - リテラルで"Error"という文字列にマッチ

したがって、このパターンは「"class"で始まり、その後に任意の文字列（0文字以上）が続き、最後に"Error"で終わる」という文字列を検索します。

## マッチする例

以下のような文字列にマッチします：

- `class StandardError`
- `class CustomError`
- `class MyApplicationError`
エラー「無効な数字です。数値は 32 ビットで表記される数値です。」

このエラーは、下記のような場合に見られる。

* /aオプションを付けてのsetにおいて、数値以外を対象にしたとき
* /aオプションを付けてのsetにおいて、batで扱える範囲(※)外の数値を対象としたとき

※batで扱える範囲の数値
符号付32ビットで表現できる範囲。
すなわち【-2147483648 ～ 2147483647】の範囲。
Windowsバッチ(.bat)学習メモ　日付(yyyymmdd)に対するチェック

* ※yyyymmdd、という8桁の半角数字以外の値が渡された場合は、
一切の例外を認めずに弾くようになってしまっています。
×：半角数字以外が含まれる文字列
×：半角数字のみで構成されているが、8桁ではない文字列


```bat:1_Controller.bat
@echo off

set modelBat="%cd%\2_Model.bat"
set wantChkTarget=任意の日付(yyyymmdd形式)
call %modelBat% %wantChkTarget%
```

```bat:2_Model.bat
@echo off
setlocal enabledelayedexpansion

::1.引数チェック（個数が適切かどうか）
if "%1"=="" set errMsg=引数がありません。
if not "%2"=="" set errMsg=引数が過剰です。
if not "!errMsg!"=="" goto incorrectArgs
:: ↑ if not defined errMsgでいけるかと思ったけど、駄目そう...？
set yyyymmdd=%1

::2.引数チェック（値が数値であるかどうか）
set /a dummy=%yyyymmdd% 2>nul
:: ↑ 「>nul」だとエラーメッセージは出力されてしまうので、「2」を追加してそれも抑制する
if %errorlevel% neq 0 (
    set errMsg=第一引数は、8桁の半角数字によるyyyymmdd形式の文字列で、基準日を指定してください。　入力：%yyyymmdd%
    goto incorrectArgs
)

::3.引数チェック（存在する年月が指定されているかどうか）
::3-1.桁数をチェック（yyyymmdd形式で入力されていれば、8桁になる）
set dummy=%yyyymmdd%
set count=0
:chkDigit
set dummy=!dummy:~1!
set /a count+=1
if not "!dummy!"=="" (
    goto chkDigit
) else (
    if not !count! equ 8 (
        set errMsg=第一引数は、8桁の半角数字によるyyyymmdd形式の文字列で、基準日を指定してください。　入力：%yyyymmdd%
        goto incorrectArgs
    )
)
::3-2.月部分をチェック
set yyyy=%yyyymmdd:~0,4%
set mm=%yyyymmdd:~4,2%
set dd=%yyyymmdd:~6,2%
if %mm% lss 1 if %mm% gtr 12 (
    set errMsg=第一引数で、存在しない月が指定されています　入力：%yyyymmdd%
    goto incorrectArgs
)
::3-3.日部分をチェック
::3-3-1.月ごとの最終日を取得
set maxDatePerMonth=31 28 31 30 31 30 31 31 30 31 30 31
if %mm% equ 2 (
    set reminderOfFour=%yyyy% %% 4
    set reminderOfOneHun=%yyyy% %% 100
    set reminderOfFourHun=%yyyy% %% 400
    if %reminderOfFour% equ 0 if %reminderOfOneHun% equ 0 if %reminderOfFourHun% neq 0 goto notUruuYear
    set maxDatePerMonth=31 29 31 30 31 30 31 31 30 31 30 31
)
:notUruuYear
::3-3-2.月初から月末の間に日が入っているか確認
set /a dummy=%mm%+0
set dummyToken=!dummy!
for /f "tokens=%dummyToken%" %%m in ("!maxDatePerMonth!") do set dummy=%%m
if %dd% lss 1 if %dd% gtr !dummy! (
    set errMsg=第一引数に、存在しない日付が指定されています。　入力：%yyyymmdd%
    goto incorrectArgs
)

::4-A.正常終了
.echo
echo チェック完了、問題なし
echo 引数：%yyyymmdd%
.echo
exit /b

::4-B.異常終了
:incorrectArgs
echo.
echo --------------------------------------------------
echo 処理中止
echo 原因：!errMsg!
echo --------------------------------------------------
echo.
echo 何かキーを押すとウィンドウが閉じます...
pause>nul
exit
```
Vercel, Flask初心者がサンプルアプリのデプロイで躓いたところのメモ

簡単なLINE botを作ってみようと思い立ち、[こちら](https://qiita.com/nozomiyamada/items/dff5f240e8c936d731fd)や[こちら](https://zenn.dev/shinshinki/articles/3dc4a769a1364d)の記事を参考にLINE bot用のAPIをVercelに立てようとしたのですが、かなり手こずったので、手こずった箇所のメモを備忘録用に書いておきたいと思います。

### ディレクトリ構成

最初は以下のような構成にしていましたが、
```
my_app/
　├ app.py
　├ requirements.txt
　└ vercel.json
```

以下の設定でなぜかパスが見つからないと404エラーになり、途方に暮れていました。

```vercel.json
{
  "rewrites": [
    { "source": "/(.*)", "destination": "/app" }
  ]
}
```

後でvercelが挙げているサンプルのflask appの構成を見たところ、`api/index.py`と言う構造になっており、この`index.py`内から呼ばないといけないらしいと言うことがわかり

```
my_app/
　├ api/
　│　└ index.py
　├ requirements.txt
　└ vercel.json
```
構造にし、以下の設定に変えたところ無事表示されました。。なぜなの？

```vercel.json
{
  "rewrites": [
    { "source": "/(.*)", "destination": "/api/index" }
  ]
}
```

### handlerと言う変数名

なぜかhandlerを使うところで、idsubclassエラーが出てさっぱりわかりませんでした。。

```
if not issubclass(base, BaseHTTPRequestHandler) 
```

[こちら](https://www.wongwonggoods.com/all-posts/python/python-misc/python-debug-error/vercel-if-not-issubclass-basehttprequesthandler/)の記事によると、どうも`handler`と言う変数名がvercelのpythonアプリだと使えないらしい...

そうなの？

サンプルコードだと
```
handler = WebhookHandler(os.environ["LINE_CHANNEL_SECRET"])
```
と書いているところが多いが、これを`line_handler`にしたところ、出なくなった。

### 環境変数が反映されない
これは他の記事でも書いてあるところがあるものの、環境変数は一連の「デプロイ」前に設定しておかないとダメらしい。自分の場合はGithubのリポジトリ連携していたので、pushするたびにデプロイが走っていたが、全然環境変数が読み込まれなくて焦った。

Githubからのpush履歴経由でのデプロイの場合は、デプロイキャッシュが使われるのかもしれない。
とりあえずredeployボタンを押して、デプロイし直したところ環境変数が読み込まれた。

### ルート以外に置いたファイルが読み込まれない

以下のディレクトリでapi/index.pyファイルからtoken.jsonを読み込みたかった場合に、ファイルパスとして`./token.json`を指定したが、ローカルならもちろんこのコードは動くものの、vercel内でこのindex.pyを実行するとtoken.jsonが見つかりませんエラーが出て悩まされた。あるんだが???

どうもvercelでファイルを読み込むときに、実行しているファイルからの相対パスではなく、実行しているアプリのルートディレクトリから読み込まれるらしく、ルートディレクトリにこのtoken.jsonを置いたところ（index.py内でのパス指定は変えず）無事に読み込まれた。
vercel、落とし穴がたくさんありすぎる。。。

これを
```
my_app/
　├ api/
　│　└ index.py|
  │　└ token.json
　├ requirements.txt
　└ vercel.json
```

こうした。
```
my_app/
　├ api/
　│　└ index.py|
　├ requirements.txt
  ├ token.json
　└ vercel.json
```

### 終わりに
vercel.jsonの書き方についても、ある程度ググった後にVercelが出しているサンプルアプリのソースまで見ないと最新のプラクティスがわからなくて困った。うーむ。
新人エンジニアが、Pythonのデコレータに苦しんだので勉強してみた

今回は、pythonのデコレータについてまとめてみます。

### 1. デコレータとは

デコレータは、関数のコードを変えずに、処理を追加したり変更したりできる関数です。組み込みで用意されているものもありますが、自作することもできます。

例えば、機密データをクエリするAPI、社内ドキュメントにアクセスするAPIがあるとします。これらのAPIは、はじめに認証を行い、正しいリクエストだった場合のみ、データを返したり、ドキュメントを参照したりする仕様にします。これを各々の関数で行うとき、以下のような処理の流れになります。

```python
def query_data():
		# ①認証処理
		# ②クエリ
		
def load_document():
		# ①認証処理
		# ②ドキュメントの読み込み
```

しかし、認証が必要となる全ての関数で、認証処理を書くのは億劫です。そこで、認証処理の部分を、デコレータを使って、共通化することができます。

```python
def authorize():
		# 認証処理

@authorize
def query_data():
		# クエリ
		
@authorize
def load_document():
		# ドキュメントの読み込み
```

### 2. デコレータを使うメリット

デコレータを使うと、先述の通り、重複コードを排除したり、共通処理を分離することでコードの再利用性を高めることができます。また、デコレータを使うことで、その処理の内容を一目で把握できるようになり、可読性が上がったり、修正コストの削減やテストの簡素化によって、保守が簡単になります。

### 3. デコレータの作り方

今回は、a + bの結果を返すaddメソッドに、「処理をはじめます」「処理が終わりました」という文字列を出力するデコレータを加えます。

※ コメントで解説を入れます

```python
# pre_postの引数に、add()を受け取る
def pre_post(func):
		# add()が受け取った引数を、wrapper()で受け取る
		def wrapper(*args, **kwargs):
				 print('処理をはじめます')
				 # pre_post()で受け取った関数（add）を実行する
				 func(*args, **kwargs)
				 print('処理が終わりました')
		 return wrapper

@pre_post
def add(a, b):
		result = a + b
		print(f'result: {result}')
		
add(3, 5)  # 出力：処理をはじめます/ 8 / 処理が終わりました
```

### 4. 最後に

とってもわかりやすかった動画を貼っておきます。

https://youtu.be/A4md-u022MY?si=tQX3tXL1KFF6AiJi
【Rails】ActiveSupport＃delegate 

# はじめに
`Object#try` に代わる選択肢として下の記事で紹介されていた、`ActiveSupport#delegate` について調べた内容をまとめます。

https://techracho.bpsinc.jp/hachi8833/2022_04_07/47820

# 定義
### 前提
- UserモデルとProfileモデルが `has_one` で関連付けられている（userごとにprofileが一つ存在する）
- リンクカラム（ `user_id` ）はProfileテーブルに存在する
- `user.pofile.name` のようにProfileテーブルのユーザー名を取得したい
```rb
class User < ApplicationRecord
  has_one :profile
end

# delegateマクロを使わない場合、nameメソッドを追加するとuser.nameでアクセスする
def name
  profile.name
end
```
### 定義方法
- 上記をdelegateを使って下記のように書き換える
```rb
class User < ApplicationRecord
  has_one :profile

# delegateマクロを使うとnameメソッドを下記のように書き換えができ、user.nameでアクセスする
  delegate :name, to: :profile
end
```
### 補足

#### `:allow_nil` オプション
- 対象がnilの場合、`NoMethodError`が発生する
- `allow_nil: true` を渡すと例外の代わりにnilが返る
```rb
delegate :name, to: :profile, allow_nil: true
```
#### `prefix` オブション
- 生成されたメソッドの名前にプレフィックスを追加する 
```rb
# profile_nameが生成される。上記の例ではuser.profile_nameでアクセスする
delegate :name, to: :profile, prefix: true
```
```rb
# avatar_nameが生成される。上記の例ではuser.avatar_nameでアクセスする
delegate: :name, to: :profile, prefix: avatar
```
#### `:private` オプション
- デフォルトではpublicメソッドなので　`private: true` を渡してメソッドのスコープを変更する
```rb
delegate :name, to: :profile, private: true
```
#### 複数のメソッドがまとめて指定できる
```rb
delegate :name, :age, :address, :twitter, to: :profile
```
#### `delegate_missing_to`
- オブジェクト内にある呼び出し可能なもの（インスタンス変数、メソッド、定数など）を対象に、スコープがpublicなものを委譲する

```rb
class User < ApplicationRecord
  has_one :profile

  delegate_missing_to :profile
end

# user.name、user.ageなどでアクセスできるようになる
```

# おわりに
- `allow_nil: true` とするとNoMethodErrorの例外が発生せず、Object#tryと結果が同じになります。しかし、より癒着が弱く、コードが明確という点から、ActiveSupport#delegateの方が適切と言えるようです。

- `user.profile.name`　や　`user.profile.try(:name)` はオブジェクト間の癒着が強く好ましくないので、delegateマクロを使わない場合は下記のように書き換える方が正しいようです。 
```rb
class User
def profile_name
  profile.try(:name)
  end
end
```
```rb
class User
def profile_name
  return nil if profile.nil? # nilになるのが正しい場合はガード節で早期にnilを返す
  profile.name
  end
end
```

# 参考
https://railsguides.jp/active_support_core_extensions.html#%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AE%E5%A7%94%E8%AD%B2
PowerApps ForAll を使う時、よくbugを発生します

# 問題があるソースコード
```
ForAll(colA,
Filter(test_table,id=ThisRecord.id) And ThisRecord.status='Edit'
Patch(test_table
{id= ThisRecord.id},
{
status:ThisRecord.status
}
);
);
```
# 問題点
Filter(test_table,id=ThisRecord.id)のThisRecord.idは曖昧です。
ForAllを利用するとき、ForAll(colA As parentRecord,のように使うことをお勧めします。

# 修正後のソースコード
```
ForAll(colA　 As parentRecord,
Filter(test_table,id=parentRecord.id) And parentRecord.status='Edit'
Patch(test_table
{id= parentRecord.id},
{
status:parentRecord.status
}
);
);
すごいどうでもいい用途で Node.js を使いたかった (CLIを書く)

# やりたいこと

- 言語として，Node.js が入っている前提のレポがあった
- そこで，ちょっとしたファイル操作が追加で必要になった
- シェルスクリプトでやっても良かったけど，Docker 環境でもないので，OS 依存の何かがあるのも面倒に感じた

## もうちょっと細かく

めっちゃ `sed` な感じなだけなので，

- 同期でいい
- fs
    - [readFileSync](https://nodejs.org/api/fs.html#fsreadfilesyncpath-options)
    - [writeFileSync](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options)
- String
    - [replace](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace)
- process
    - [argv](https://nodejs.org/api/process.html#processargv)

こんなだけで良かった．

## まとめ

たまには違うことをやるのもいい

## Refs

https://jsprimer.net/use-case/nodecli/argument-parse/

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace

https://qiita.com/wifeofvillon/items/b307306eed08d8a7b4f4
Rustでsqlx(PostgreSQL)を使う

# PostgreSQL側のコマンド
### データベースの操作
ターミナルにて、
- デフォルトのデータベースに接続
```bash
$ psql -d postgres
```
- データベースの一覧を表示
    
```bash
$ \l
または
$ SELECT * FROM pg_database;
```
ここで、`postgres`,`template0`,`template1`と名付けられたデータベースは初期からあるデータベースで、`postgres`がデフォルトになっている

- データベースの作成
```bash
$ CREATE DATABASE {データベース名};
```
ただし、データベース名に大文字を付けたい場合は、データベース名を`"二重引用符”`でくくる

- データベースの削除
```bash
$ DROP DATABASE {データベース名};
```

- データベースの選択
```bash
\c {データベース名}
```
### sqlxコマンド
- 終了する
```bash
$ postgres=# \quit
```

# 環境設定
**sqlx-cliをインストールする**
今回はPostgreSQLを使います。
```bash
cargo install sqlx-cli --no-default-features --features native-tls,postgres
```

**データベースを作成する**
```bash
sqlx database create
```

**マイグレートする**
例としてusersをマイグレートする
```bash
sqlx migrate add -r users
```

migrationsに２つのファイルが生成される
- downにはDropに関するsql
- upにはテーブルを作成するsql

をそれぞれ記述する

**マイグレーションを実行する**
```bash
sqlx migrate run
```
【備忘録】Rustのgen記法について

# gen記法
実は、Rustの2024 editionからgen記法がRustで使えるようになります。

yieldは、関数を一時的に実行停止させることが出来る機能を持つ文で、gen記法と組み合わせることで、イテレータを作ることができます。

python yieldで調べると、わかりやすい説明が出てくるでしょう。

Rustの説明はこのとおりです。

https://rust-lang.github.io/rfcs/3513-gen-blocks.html

書き方はこんなかんじ。

```rust:Rust
gen {
    loop {
        yield 0;
        yield 1;
    }
}
```

```python:Python
def gen():
    while True:
        yield 0
        yield 1
```
docker command 覚書

# Dockerコマンド覚書

## `docker ps`で出力される内容

Dockerのdocker psコマンドは、現在実行中のコンテナの一覧を表示するためのコマンドです。

出力内容
docker psコマンドを実行すると、通常以下のような情報が表示されます。

CONTAINER ID: コンテナの一意な識別子
IMAGE: コンテナが基づいているイメージ名
COMMAND: コンテナ内で実行されているコマンド
CREATED: コンテナが作成された時刻
STATUS: コンテナの状態（Up、Exitedなど）
PORTS: コンテナに公開されているポート
NAMES: コンテナ名

## Container名のみ表示したい時

Container名に"hogehoge"を含むcontainerの名前リストが出力される。

```bash
% docker ps --format '{{.Names}}'
```

出力例
```
my_web_app
my_db
```


## すべてのコンテナのコンテナ名を表示

```bash
docker ps -a --format '{{.Names}}'
```

## 停止中のコンテナのコンテナ名を表示

```bash
docker ps --filter="status=exited" --format '{{.Names}}'
```
【テスト技法】同値テストと境界値テスト

# はじめに
こんにちは。アメリカで独学でエンジニアを目指している者です。
現在、Railsの勉強をしていますが、並行してソフトウェアテスト技法を学ぶことで、Railsチュートリアルの理解度が向上すると考え、テスト技法の勉強も始めました。
その際に学んだ同値クラステストと境界値テストについて、記憶が薄れる前に簡単にまとめておきたいと思います。

ちなみに、テスト技法はUdemyで勉強しています。とても分かりやすいので、テスト技法を勉強したいと思う方はぜひ見てみてください。

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

## ソフトウェアテスト技法
そもそもソフトウェアテスト技法とは何でしょうか。
動画上でソフトウェアテスト技法は以下のように定義されていました。
> 現実的に実行できるレベルの量までテストケースを削減しつつ、少ないテストケースでも品質を保証できるように最適なテストケースを設計すること

できればすべてテストできた方が良いですが、テストケースが途方もなく増えてしまうため、最低限の労力で適切なテストを行う技術を指します。。

## 同値クラステスト

まずは以下の例を見てください
```ruby
if a == 2
  # 処理
elsif a ==  10
  # 処理
else
  # 処理
end
```

上記のようなコードがあった場合、何通りのテストを行えばよいでしょうか。

答えは a = 2、a = 10、a = 4（他にもあります）の3通りです。
a = 4 は3や10以外の任意の数値を選ぶことができ、同様に他の値でも問題ありません。
これにより、すべての処理をテストすることができます。このようなテスト技法を同値クラステストといいます。

## 境界値テスト

今回も同様、以下のコードをみてください
```ruby
if a <= 2
  # 処理
elsif a >= 10
  # 処理
else
  # 処理
end
```

上記のコードがあった場合、何通りのテストを行えばよいでしょうか。
私は a = 2、a = 10、a = 5 の3通りと答えてしまいましたが、正解は a = 1、a = 2、a = 3、a = 9、a = 10、a = 11 の6通りです。
私の答えでも基本的にはすべての処理をテストすることができますが、コードを書いている際に以下のような間違いをしてしまったらどうでしょうか。

```ruby
if a < 2 # =を書き忘れてしまった
  # 処理
elsif a >= 10
  # 処理
else
  # 処理
end
```
人は誰しも間違いを犯す可能性があります。このようなミスがある場合、私の答えではすべての処理をテストできなくなってしまいます。
このように、境界値（a = 2 や a = 10）およびその前後の値でテストを行うことを境界値テストといいます。


## まとめ
本日はテスト技法の中でも同値クラステストと境界値テストについて記事にしてみました。
同値クラステストは知らなくても自然にできましたが、境界値テストは知らないとテストコードを書けないことがわかりました。
このようなテスト技法の知識を深めることで、Railsで書くテストの質を向上させていきたいと思います。
AWSの業務の実行スケジュールを柔軟に変更する方法

## はじめに
日々の業務で定期的に実行している処理のスケジュールを、急な変更や特別な事情に合わせて変更したいと思ったことはありませんか？例えば、サービスのバージョンアップや営業時間の変更、キャンペーンの実施などで、スケジュールの柔軟な対応が必要になることがあるかもしれません。
Amazon EventBridge Schedulerで運用している場合は、一度スケジュールを無効にしてから新しいスケジュールを設定し、実行後に元のスケジュールを再度有効にするなど、スケジュールの作成・削除や無効化・有効化といった工夫が必要です。クラウド型ジョブスケジューラーサービスを利用すると、業務処理の実行スケジュールをGUIで柔軟に変更できます。
以下のようなケースで実際に試してみました。

**定期実行処理の中止**
**ユースケース**: サービスのバージョンアップに伴い、毎日実行しているデータ連携処理を明日のみ中止する。

**定期実行処理の変更**
**ユースケース**: 店舗改装など短縮営業に伴い、営業日20時に実行している売上集計処理の時刻を月末3日間のみ18時に変更する。

**定期実行処理の追加**
**ユースケース**: キャンペーン実施に伴い、毎週金曜日に実行しているマーケティングデータ集計処理を1月のみ毎週水曜日も追加する。
<img width="700" alt="BeforeAfter.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/cab41336-bc52-e874-ba66-a73d75b13b66.png">
## 準備
クラウド型ジョブスケジューラーサービスで、カレンダー、イベント送信先、ジョブを作成しておきます。クラウド型ジョブスケジューラーサービスの詳細な設定手順については、以下の記事をご参照ください。

https://qiita.com/hs-matsu/items/3e8ff328cb3dccc0df5f

## 実行スケジュールの一時変更手順
業務処理は、クラウド型ジョブスケジューラーでは「ジョブ」に相当します。ジョブの実行スケジュールを変更することで、業務処理の一時変更（中止・変更・追加）ができます。
### 定期実行処理の中止

ここでは、毎日実行しているジョブを特定の日のみ中止する方法を説明します。例では明日の1時の実行予定を中止します。
**手順**
1. **[ジョブ編集]画面を開く**
   クラウド型ジョブスケジューラーサービスにサインインし、対象ジョブの[ジョブ編集]画面を開く
2. **中止したい日付を選択する**
   カレンダーから中止したい日付（例: 明日）を選択する
3. **[実行予定の一時変更]ダイアログを開く**
   中止対象の実行予定日時（例: 1時）の行をクリックし、[実行予定の一時変更]ダイアログを開く
4. **中止設定をする**
   [実行予定の一時変更]ダイアログで「中止」を選択し、[OK]ボタンをクリックする

**確認**
実行予定の一覧に、中止した実行予定（例: 明日の1時）が表示されなくなりました。
<img width="700" alt="ジョブ中止.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/5637263b-58dd-89ba-4cd4-353208b09e9f.png">

### 定期実行処理の変更
ここでは、特定の期間のみジョブの実行時刻を変更する方法を説明します。例では営業日20時に実行しているジョブを、月末3日間のみ18時に変更します。
**手順**
1. **[ジョブ編集]画面を開く**
   クラウド型ジョブスケジューラーサービスにサインインし、対象ジョブの[ジョブ編集]画面を開く
2. **変更したい日付を選択する**
   カレンダーから変更したい日付（例: 月末の3日間）を選択する
3. **[実行予定の一時変更]ダイアログを開く**
   変更対象の実行予定日時（例: 20時）の行をクリックし、[実行予定の一時変更]ダイアログを開く
4. **変更設定をする**
   [実行予定の一時変更]ダイアログで「変更」を選択し、[時間]に変更後の時刻（例: 18時）を入力し、[OK]ボタンをクリックする
   
特定の期間の日数分、手順を繰り返します。

**確認**
実行予定の一覧に、変更後の実行予定（例: 月末の3日間のみ18時）が表示されます。
<img width="700" alt="ジョブ変更.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/e64e259a-67a3-7894-4cab-71dbca42078e.png">

### 定期実行処理の追加
ここでは、特定の期間のみジョブを追加する方法を説明します。例では毎週金曜日に実行しているジョブを、1月のみ毎週水曜日も追加します。
**手順**
1. **[ジョブ編集]画面を開く**
   クラウド型ジョブスケジューラーサービスにサインインし、対象ジョブの[ジョブ編集]画面を開く
2. **追加したい日付を選択する**
   カレンダーから追加したい日付（例: 1月の水曜日）を選択する
3. **[実行予定の追加]ダイアログを開く**
   [実行予定の追加]ボタンをクリックし、[実行予定の追加]ダイアログを開く
4. **追加設定をする**
   [実行予定の追加]ダイアログで、[時間]に追加する時刻（例: 12時）を入力し、[追加]ボタンをクリックする

特定の期間の日数分、手順を繰り返します。

**確認**
実行予定の一覧に、追加した実行予定（例: 1月の水曜日12時）が表示されます。
<img width="700" alt="ジョブ追加.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889837/300dd7ff-f401-c4c9-483a-d70fced4d033.png">

## まとめ
この記事では、クラウド型ジョブスケジューラーサービスを利用して、業務処理の実行スケジュールを柔軟に変更する方法を紹介しました。具体的には、ジョブの実行予定の中止、実行予定日時の変更、新たな実行予定の追加を、GUIを通じて簡単に行う手順を解説しました。業務の効率化や柔軟な対応の一助となれば幸いです。

## 参考リンク
- 株式会社日立ソリューションズ
\- クラウド型ジョブスケジューラーサービス　ご紹介サイト
https://www.hitachi-solutions.co.jp/jobschedulerservice/
【TeamDeveloper】チェックボックスにチェックを入れる方法

# 問題
プログラムでチェックボックスにチェックを入れたい場合。
以下のようにチェックボックスの名前をベタで指定する場合はそのまま通ります。
```:OK
Set cb1 = TRUE
```
が、ウィンドウハンドルを使用する場合はこのままだと通りません。
```:NG
Set hWndItem = TRUE
```

# 解決策
Team Developer7.3以降の場合ですが **SalSetButtonChecked関数**を使うと可能になります。
```
Call SalSetButtonChecked( Handle, nCheck )
```
nCheck = 1 はチェックあり
nCheck = 0 はチェックなし
返り値はTrue or false っぽい

なぜか公式ドキュメントに載っていなかったので見つけるのに苦労しました……。
言語がマイナーすぎる故なのかな。
You may be prompted to give access to control Xcode. Flutter uses Xcode to run your app. If access is not allowed, you can change this through your Settings > Privacy & Security > Automation.

## エラー本文
```
You may be prompted to give access to control Xcode. Flutter uses Xcode to run your app. If access is not allowed, you can change this through your Settings > Privacy & Security > Automation.

Oops; flutter has exited unexpectedly: "SocketException: Send failed (OS Error: No route to host, errno = 65), address = 0.0.0.0, port = 5353".
A crash report has been written to /Users/user-name/your-project/flutter_02.log
```

## エラーの翻訳
Xcodeをコントロールするためのアクセス権を与えるようプロンプトが表示されるかもしれません。FlutterはXcodeを使ってアプリを実行します。アクセスが許可されていない場合は、設定 > プライバシーとセキュリティ > オートメーションから変更できます。

## 発生手順
AndroidStudioのコンソール及び、RunボタンでiOS用のビルドを実行すると上述のエラーが出る

## 発生した環境
- macOS Sequoia 15.2
- AndroidStudio LadyBug及びAndroidStudio Jellyfish
- Xcode16.2
- Flutter 3.27.3
- cocoapod 1.16.2

## 回避策
VSCodeを使用してビルドを実行し、途中で出てくるポップアップを許可する
### キャンセルした場合は
リンゴマーク > システム設定 > プライバシーとセキュリティ > ローカル ネットワーク > VsCodeのtoggleをオンにする

※AndroidStudioでの解決方法は見つかりませんでした。また最新版であるのAndroidStudio Meerkatのリリースにも修正内容として上記の対応は書かれていませんでした。

## 原因
詳しくはないのですが、AndroidStudioのCommandLineToolがおかしいのではないかと言われてますね

## 参考

https://github.com/flutter/flutter/issues/150131
HugeDomainsでドメインを買ってからNameBrightでDNSを設定したいとき

## 概略
HugeDomainsでドメインを買うと、そのドメインはNameBrightというアメリカの有名なレジストラで受け取ることになる。
最初の決済が完了してから24時間ほどで、HugeDomainsからNameBrightのアカウントが送られてくる。

HugeDomainsは、丁寧にNameBrightでDNSを設定する手順を書いてくれているのだが、重大な手順が抜け落ちていて**購入したドメインが見つからない**ということが発生したので、本記事ではその重大な手順を書いておく。

## 本文
### 事前作業
まず、NameBrightは現在betaとlegacyと、二種類のバーションが存在する。HugeDomainsからはbeta(こちらのほうが新しい)に誘導されるが、legacyを使うのが正解だ。

👇NameBright(legacy):

https://legacy.namebright.com

legacyへアクセスしたら、HugeDomainsからメールで届いているアカウントを入力してログインする。メールに認証コードが届くので入力する。

ログインすると、メールアドレスの確認が求められるが、これはメールが届かないので無視して構わない。

そして、左上を見るとDOMAINS(0)となっていて、自分の購入したドメインが見つからないはずだ。ここが本記事で解決したい問題である。

### 購入したドメインへのアクセス

購入したドメインを見つけるには、ページ右上の選択ボタンをクリックする。そこに「hdsalesagreements」という項目があるので選択する。

すると、購入したドメインに関連するページが表示されるので、諸々の設定を済ませ、左上のDOMAINS(1)から購入したドメインを選択する。するとDNS等の設定ページが表示されるので、あとは必要な設定をおこなえばOKである。

い
Why Choose Flutter for Your Next App Development Project?

![1  Why Choose Flutter For Your Next App Development Project.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493374/aba7fd14-3b74-ddad-4cc2-3e6a232b1dcc.jpeg)
Flutter is a phone programming framework that has gained popularity among developers worldwide. It contains all of the components from cross-platform and native development models needed to create powerful apps in a short period.

Many organizations seek to employ a Flutter application development company to develop applications that serve a large audience. You can select an economic corporation that meets your organization's needs.

Numbers that Flutters!
According to Tim Sneath, Google's product manager for Flutter and Dart, over two million developers have used Flutter in the sixteen months since it was released. According to his assessment, despite the circumstances created by the COVID-19 epidemic, March experienced a 10% month-over-month gain.

Approximately 500,000 developers now use Flutter to construct mobile applications.

According to Statista, Flutter is the second most popular cross-platform mobile framework among developers globally. It also claims that 39% of coders utilize Flutter, a 9% rise from the previous year.

According to a recent Stack Overflow survey, 68.8% of developers adore Flutter and are eager to learn more about the technology. According to their statistics, Flutter is one of the least terrible and most desired applications.

According to Google Trends, interest in Flutter grew in the United States last year. The graphic below illustrates that blue represents Flutter and red means React Native. In global data, the pattern is nearly identical.

Flutter has approximately 109k ratings on GitHub, a large number compared to other technologies. It is also one of GitHub's top 50 most active repositories.

These figures show an increase in the use of Flutter for developing mobile applications. It is a new trend, and many coders appear to agree with it. This should motivate many mobile app development service providers to learn Flutter and offer it to their clients. Here are some more statistics that demonstrate the technology's popularity.

Since the technology's inception, over 100,000 apps have been released, according to Flutter. Realtor.com, Tencent, The New York Times, Square, and Google Assistant are among the most popular Flutter apps.

Statista says 7.2% of developers worldwide use Flutter libraries, frameworks, and tools as of early 2020.

Dart is the fastest-growing language between 2018 and 2019, according to studies. It is the language in which the Flutter framework is implemented. Over the next two years, they predict a massive 532% increase in total consumption.

Other prominent Flutter applications include Google Ads and Alibaba Group, with over 60 million downloads combined.
【GTM】カルーセル内でのモーダル表示計測

## 背景と要件
キャンペーンサイトの制作にて、リアル店舗で利用できるクーポン情報をモーダルで実装。
モーダル内の要素としては、以下のような情報を記載。

![Qiita01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3924179/28486c85-f930-f16d-90ed-3d97cfda5c27.png)

店舗別にどれだけモーダル（クーポン情報）が表示されたか計測が必要。

## 対応方針
過去の経験上、モーダル表示のトリガーとなるボタンのクリック数を計測すれば、イコール表示回数になるでしょ！ってことで、いつも通りクリックイベントを仕掛けつつ、モーダル内の店舗名を取得できるようにカスタムJavaScriptで変数設定を追加。
あとは、プレビューでタグの発火が確認できれば完了！と思ってテストしてみたところで、予想していなかった問題が発生、、！

## クリックイベントが使えない！
今回は、モーダル表示のトリガーとなる要素がカルーセル内に実装されているため、モーダルを開く動作以外にも、横スクロール時のクリック（タップ）でクリックイベントが発生してしまうという事態に、、、

![Qiita02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3924179/e698d80c-3040-a978-60b5-93df1228df8c.png)

よく考えれば、事前に分かりそうなものだが、クリックイベントでイケるだろうと高を括っていたのが良くなかった。
もう頭の中は「クリックイベント」という考えしかなく、どうすればモーダル表示のクリックだけ取得できるか試行錯誤、、、
JavaScriptのclickとかtouchとかmousemoveとかのイベントを駆使して、「一定時間以上イベントが継続したら発火させない」みたいなロジックをコネコネしてみましたが当然安定せず。。。
（人によってフリックする動作の時間なんて違うでしょっていうのは冷静になればわかる）
公開日に追われつつ途方に暮れかけたとき、今回の要件にうってつけのトリガーを発見！

## 要素の表示トリガーで解決！
モーダルの表示回数を計測するために存在するような「要素の表示」というトリガーを発見！
今までなぜ知らなかったのかと思うくらいとても便利な機能ですが、設定自体はとても簡単。

:::note info
**要素の表示トリガー**
Google タグ マネージャーの要素の表示トリガーは、選択した要素がウェブブラウザのビューポートに表示されると発動します。要素を表示させるイベントには、ページの読み込み、ページのスクロール、ブラウザタブのフォアグラウンドへの移動、要素の位置や表示に影響を与える自動タスクなどがあります。
:::
参考：https://support.google.com/tagmanager/answer/7679410?hl=ja

### 要素（モーダル）の表示トリガーの設定内容

![Qiita03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3924179/8486dd7b-283f-ba44-5b6d-ab34ff275e07.png)

- **トリガーのタイプ**：要素の表示
- **選択方法**：ID（CSSセレクタでも可）
- **要素ID**：モーダル内のID名を設定
- **このトリガーを起動するタイミング**：各要素が画面に表示されるたび
- **DOMの変更をモニタリング**：チェック
- **このトリガーの発生場所**：すべての表示イベント（条件によってよしなに設定）

:::note warn
**親要素のIDではイベントが発火しない可能性あり**
要素IDにはモーダルの親要素のIDを設定したくなるが、今回それでは動かなかったので子要素のIDを設定。
プレビューでの検証時に発火しなくて一瞬焦るが、設定するIDやclass名を変更して再度テストすれば問題なく動くはず。
:::

![Qiita04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3924179/fcaf0a03-7fc9-8baa-c036-5ee1c5c29867.png)

## 最後に
GTMの設定などは後回しにしがちなので、事前にある程度チェックしておくことが大事だなと反省。経験則に頼って予想で動くと痛い目をみるなと。。。
とはいえ、やはりGoogleさんはすごいですよね。痒いところに手が（届かない時もありますが）届くような機能はだいたい存在します。

アルビド・ジャパン株式会社では、各種ツールの計測設定やマンスリーレポートの作成なども承っておりますので、お気軽にご相談くださいませ！
Linear API:Working with the GraphQL APIのサンプルコードをGithubで公開しました。


## この記事の対象読者
Linear公式のGraphQL APIページを見て、Pythonでクエリを試したがうまくいかなかった人
https://developers.linear.app/docs/graphql/working-with-the-graphql-api

忙しい人は、以下にコードを公開していますので読むと速い。
https://github.com/akjava/python-linear-api-examples/tree/main/examples/api

上記のページのクエリをすべて動く、サンプルを分けて、intro*.pyで作ってみました。

***クエリとは、GraphQL APIに対してデータを要求するための以下のようなテキストのこと***
```
   query Me {
  viewer {
    id
    name
    email
  }
}
```

## GraphQLとは
GraphQLは、RESTと同じようにHTTPプロトコルを使って通信しますが、より効率的なデータ取得を実現します。

より詳しくは、公式の英文をAIに聞く方が正確でしょう。https://graphql.org/

## PythonでLinear APIを呼び出し時の注意点
GraphQLは、他に使ったことないので、同じかどうかはわかりません。

### queryで送る
queryでも、mutationでも、queryとして送るみたいです。
```
query_dic = {"query": query_text}
...
response = requests.post(url, headers=headers, json=query_dic)
```

### 返ってきた値から目的値の取得
例として、送ったのが以下の構造だと(なお、大文字から始まるTeamsは何の意味もないです)
```
query Teams {
  teams {
    nodes {
      id
      name
    }
  }
}
```
最初にdataがつけて、値を取り出します。
```
first_team_id = result["data"]["teams"]["nodes"][0]["id"]
```
## 削除したデータの取得
基本、削除されたデータは３０日間のArchived状態になります。そしてデフォルトでは取れません。
まず、**includeArchived: true** は必須です。
公式のドキュメントには書いてませんでしたが、archivedAtの値（日付）があるデータだけを取るにはnullフィルターを使うのがいいと思います。
```
query {
  issues(includeArchived: true,filter:{
    archivedAt:{
      null:false
      }
  }) {
    nodes {
      title
      archivedAt
    }
  }
}
```
## まとめ
基本的に、pythonでもページにのっている、クエリをそのままコピーして送りつけると動きます。

あと Linear API(GraphQL)はエラーの内容が詳細に返ってくるのでメッセージを良く読みましょう。
テキスト量が多いと思ったより遅いので更新内容だけとる工夫をしないと、数が多い時に大変です。

しばらくはLinear記事続きますので、今後ともよろしく。

Github
https://github.com/akjava/python-linear-api-examples
[ABC390] ABC 390(Atcoder Beginner Contest)のA~C(A,B,C)問題をPythonで解説(復習)

# [ABC390] ABC 390(Atcoder Beginner Contest)のA~C(A,B,C)問題をPythonで解説(復習)

# A問題
- 実際に連続する箇所を入れ替えてみて，昇順に並ぶかどうかで判断する．
```A.py
"""
<方針>
- 実際に連続する箇所を入れ替えてみて，昇順に並ぶかどうかで判断する．
"""
# 入力
A = list(map(int, input().split()))

# 連続する場所の入れ替えをやってみる．
for i in range(4):
  # Aをコピーする．
  tmp = A[:]
  # 入れ替えてみる
  tmp[i], tmp[i+1] = tmp[i+1], tmp[i]
  # 揃えば，Yesを出力して，プログラムを終了する．
  if(tmp == [1, 2, 3, 4, 5]):
    print("Yes")
    exit()

# 不可能
print("No")
```

# B問題
- 連続する部分において，以下の式(比の式)が成り立つことが等比数列であることの必要十分条件(多分)である．
  - `A[i]*A[1] == A[i+1]*A[0]`
```B.py
"""
<方針>
- 連続する部分において，以下の式(比の式)が成り立つことが等比数列であることの必要十分条件(多分)である．
  - `A[i]*A[1] == A[i+1]*A[0]`
"""
# 入力
N = int(input())
A = list(map(int, input().split()))

# 順番に比を見ていく．
for i in range(N-1):
  # 比の式
  if(A[i]*A[1] != A[i+1]*A[0]):
    # 違ってればNoとしてプログラムを終了する．
    print("No")
    exit()

# 問題なければ，Yesを出力する．
print("Yes")
```

# C問題
## 方針
- 黒マスのうち，最も上下左右な位置を記録する．
- 白マスのうち，前述の黒マスの範囲に入ってなければ問題ない．
- 全てのマスを閲覧することは，`O(HW)` なので問題ない．
## 前提
- `C`問題あたりで，`TLE`になる人は，制約条件を見る癖をつけよう．
- `A`と`B`問題では，基本的に制約条件を見ずにやっても解ける．
- しかし，`C`問題以降では，制約条件を見ないと必ず`TLE`すると思っても良い．
- 詳しい話は私の[352回の記事](https://qiita.com/mattsunkun/items/837444254f03e6105922) の`C`問題の解説に記したので，是非参照してほしい．
```C.py
"""
<方針>
- 黒マスのうち，最も上下左右な位置を記録する．
- 白マスのうち，前述の黒マスの範囲に入ってなければ問題ない．
- 全てのマスを閲覧することは，`O(HW)` なので問題ない．
"""
H, W = map(int, input().split())
SS = [list(input()) for _ in range(H)]

# 上下左右を保持する．
top = H
bottom = -1
left = W
right = -1

# 黒マスをみて，上下左右を記録する．
for i in range(H):
  for j in range(W):
    # 黒マスの時
    if(SS[i][j] == "#"):
      # 更新
      top = min(top, i)
      bottom = max(bottom, i)
      left = min(left, j)
      right = max(right, j)

# 白マスを見て，問題が無いかを確認する．
for i in range(H):
  for j in range(W):
    # 白マスのとき，
    if(SS[i][j] == "."):
      # 黒マスの範囲に入っているとNG
      if((top <= i <= bottom) and (left <= j <= right)):
        print("No")
        exit()

# 上限をクリアすればOK
print("Yes")
```

# 補足
### 関係するリンク(参考文献など)
- [今回のコンテスト](https://atcoder.jp/contests/abc390)
### 筆者について
- [Atcoderアカウント](https://atcoder.jp/users/mattsunkun)
- *今回も不参加のため，成績なし．*
- [解説で示したA問題の提出](https://atcoder.jp/contests/abc390/submissions/62157750)
- [解説で示したB問題の提出](https://atcoder.jp/contests/abc390/submissions/62157877)
- [解説で示したC問題の提出](https://atcoder.jp/contests/abc390/submissions/62168168)
### その他
- **間違いを含んでいる可能性があります．**
- 方針と言いつつ，方針ではない感想などを書いている可能性があります．
- A問題から解説がだんだん省略されます．
- コードに書かれている解説の文言と，その上に書いてある解説の文言を変えている場合があります．
### 最後に一言
- D,E解けるようになりたいな．
「アジャイルデータモデリング」読書メモ

# はじめに

「アジャイルデータモデリング」を読んでみたのでメモ

https://amzn.asia/d/aZaHD3H

- データウェアハウスのモデリングに関する貴重な和書(唯一?)
- 原著は2011年で古いけど、全く古さは感じない。デザインパターンのような内容なので、すぐに古くなることはなさそう。一部最近のDWHの機能や最近の用語と違う部分もありますが、訳註などで補足されている
- スタースキーマ(の変形?)によるデータモデリングのベストプラクティス集
- データエンジニア・アナリティクスエンジニアの方向け。実務で使っていると、普段の悩み事について言語化されている。課題が簡単に解決できるとは限らないけど、共通の言語・フレームワークをベースとすることで、議論の土台にしやすそう
- タイトルに「アジャイル」とあるように、段階的にデータ基盤を改善していこう、という趣旨で書かれている
- 最後に、(本編との繋がりは大きくはないですが)日本の会社のデータ基盤についての事例がのっている

# 1 モデリング

ディメンショナルモデリング、スタースキーマ、ファクト、ディメンション、RDBとDWHの違い、といったモデリングの概要。書籍としてまとまって読めるのは助かります。

# 3.5 ディメンションの履歴

業務DBと異なり、分析DWHでは時系列の履歴データの扱いが必要になるので、なるほど感。現在の値か、イベント時点の値かは悩むことが多い。最近のDWHでは、betweenでjoinしても遅くないという補足あり。

# 4.1 適合ディメンション(conformed dimension)

似たようなテーブルがある時、カラムの名前・意味が違うと扱いにくいので、同じカラムに統一しておくと、使い勝手や効率がよくなるという話。似ているけど微妙に違うテーブルの扱いは悩むので、なるほど感。

- スワップ可能ディメンション: 同じカラムのテーブル
- ロールアップディメンション: ドリルダウン用
- ロールプレイングディメンション: 複数の意味のカラム・テーブルとjoinできる。Railsのポリモーフィックっぽい？

# 4.1.3 イベントマトリックス

この書籍の"BEAM"モデリング手法の肝の一つが「イベントマトリックス」
イベントと属性でテーブルを作り、どのイベントがどの属性を持つかの一覧表を作ることで全体像を把握する。モデリングのブレーンストーミングによさそう。

# 5.1 データプロファイリング

データの特徴を把握しましょう、という話。
- 欠損値 (非NULL制約?)
- 一意な値と頻度 (unique制約,カーディナリティ?)
- データの範囲と長さ

一意と思ったカラムが、実は一意でなかった、、、NULLでないと思ったら過去の経緯でNULLだった、、、などはよくあるので、この辺見たいところ。
実際にどう運用するかは考え所ですが、シンプルにinformation_schemaなどを使ってSQLでプロファイルしてもいい、という話。

# 8.3 発展型イベント

イベントの種類を以下の３種類に分類している。
- 離散型: 1回だけ
- 発展型: 複数の関連するイベント。アクセスログの同一セッションのような感じ？ 訪問=>サインアップ=>購入、のような？
- 反復型: サブスクリプションのような繰り替えし?

発展型のように連続するイベントの扱いは悩むことがあるので、参考になります。アクセスログのセッションや、ファネルに近いイメージと思いました。

累積スナップショットとして開発、、、とありますが、ここはいまいちイメージがわかず。強引にSQLで処理してしまうことが多そう。。。

8.5にファクトに複数の関連するディメンションをjoinすることがある場合、「派生ファクトテーブル」を作っておくとあるのは、今悩んでいるところだったので、なるほど感。(といっても手法はいまいちわからず、普通にjoinしたテーブルを事前に作っておくのでよさそう？)


# まとめ

とりあえず、ぱっと見たところを書いてみました。モデリングに関する書籍は読んだことがなかったので、体系的に言語化されてまとまっているこの書籍はとてもありがたいです。
JavaScriptで引数を関数化する方法

## 定義
```js
function functionize(v){
    // 引数vを返す無引数関数を返す
    return (() => v);
}
```

## 使用例
```js
//　100を返す関数を作成して変数に格納
const functionizedValue = functionize(100);
// 当該関数を実行した結果を表示
console.log(functionizedValue());
```
## 表示結果
```text
100
```
Next.js（Pages Router）でAPIルートからIPアドレスを取得する方法

## はじめに

Next.js（Pages Router）でAPIルートからIPアドレスを取得する方法を備忘録として残します。

## 環境

```
"next": "13.2.4",
```

## コード

リクエストのヘッダーにある`x-forwarded-for`で取得できます。

```typescript:/api/ip/getIp.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const data = {
    ip: req.headers['x-forwarded-for'],
  };

  return res.status(200).json(data);
}
```

HTTPリクエストにaxiosを使用してますが、何でも良いです。

```typescript
import axios from 'axios';

type Ip = {
  ip: string;
};

export const fetchIp = async () => {
  const { data } = await axios.get<Ip>('/api/ip/getIp');

  return data;
};
```

## 注意

ローカル環境では、プロキシサーバーなどのネットワーク機器が存在しないため、`x-forwarded-for`が取得できません。サーバーにデプロイすれば取得できるようになります。

## 最後に

### GoQSystemでは一緒に働いてくれる仲間を募集中です！

ご興味がある方は以下リンクよりご確認ください。

https://goqsystem.recruit.site?qiita=ba6a7716da2ea274bcf7
【React】StackBitzで開発したWebアプリをレンタルサーバーで公開する

## 目的
StackBitz（オンラインコードエディタ）で開発したWebアプリケーションをビルドし、レンタルサーバーにアップロードして公開することを目的とします。

### 前提条件
- MacOSを使用
- Node.jsとnpmがインストール済みであること

## 手順
### 1.StackBitzからWebアプリの構成ファイルをダウンロード
StackBitzでプロジェクトを開きます。
以下のスクショ赤枠のボタンから、構成ファイルをZIP形式でダウンロードできます。
![スクリーンショット 2025-01-28 11.30.07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3985941/a8db121a-4dda-707e-4fd8-5fc647947a19.jpeg)

### 2.Macのホームディレクトリに配置
ダウンロードしたZIPファイルを解凍して、以下のホームディレクトリに配置します。
/Users/[ユーザー名]/[ここに解凍したフォルダ名]
例では「vitejs-vite-q1t2xyaj」というフォルダ名です。
![スクリーンショット-2025-01-28-11.37.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3985941/8fb24409-b680-fa0a-1e58-c544bc1753bb.png)
補足：ホームディレクトリ内には、「/Users/[ユーザー名]/書類」や「/Users/[ユーザー名]/ダウンロード」などのフォルダがあります。

### 3.package.jsonを編集
構成ファイル「package.json」に公開URLを指定するため、最初に homepage の項目を追加します。
例: サーバーのサブディレクトリ「react」に公開する場合
```json
{
  "homepage": "https://[ドメイン名]/react/",
  "name": "vite-react-starter",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
  // 他の設定は省略
  },
  "dependencies": {
  // 他の設定は省略
  },
  "devDependencies": {
  // 他の設定は省略
  }
}
```
### 4.vite.config.jsを編集
サブディレクトリに配置する場合のみ編集が必要です。
構成ファイル「vite.config.js」の base オプションにベースパスを設定します。
例: サブディレクトリ「react」に配置する場合
```js
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  base: '/react/', // サブディレクトリに配置する場合のベースパス
})
```

### 5.publicフォルダに「.htaccess」を作成
構成ファイルの「public」フォルダに以下の内容で「.htaccess」ファイルを作成します。
```
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
```

### 6.ターミナルでビルド
ターミナルを開き、ホームディレクトリに配置したプロジェクトのフォルダに移動します。
例：「vitejs-vite-q1t2xyaj」というフォルダ名の場合
```ターミナル
cd vitejs-vite-q1t2xyaj
```
次に、ビルドを実行します。
```ターミナル
npm run build
```
### 7.ビルドされたファイルをFTPでアップロード
ビルド後、「dist」というフォルダが作成されます。
![スクリーンショット-2025-01-28-12.05.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3985941/b25f7ff1-de0c-d3c1-1991-b1bd4f918f41.png)

この「dist」フォルダ内のファイルをすべて、サーバーの公開ディレクトリへFTPでアップロードします。
※「dist」フォルダ自体をアップロードする必要はありません。
![スクリーンショット-2025-01-28-12.20.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3985941/7b9b6013-9464-d060-8bb8-6cba7db778da.png)

これで、公開URLにアクセスすると、Webアプリーケーションが公開できているかと思います。

## 最後に
Reactを学ぶためのツールは便利なものが多く、面倒な環境構築をせずともサクサク学べます。
しかし、いざ自分で環境構築・公開するとなれば、どうすれば良いかわかりません。
そのため、オンラインコードエディタで作成したプロジェクトを公開する具体的な手順を記事にしました。
【C++】Singleton(デザインパターン)

## Singletonとは?
あるクラスについて、**インスタンスが単一であることを保証する**設計。
- **複数のオブジェクトで共有したいデータ**を保持する
- オブジェクトを**1つだけ作成することに特化している**
- 一度だけ作成することで**パフォーマンスを向上**できる

### C++
```C++:Singleton.cpp
#include <iostream>
#include <string>

/// <summary>
/// シングルトン
/// 
/// templateで汎用性強化
/// </summary>
template<typename T>
class Singleton
{
public:
	/// <summary>
	/// デフォルトコンストラクタ
	/// 
	/// コンストラクタは絶対に呼ばない!!
	/// </summary>
	Singleton() {}

	/// <summary>
	/// インスタンスを取得する
	/// </summary>
	static T* GetInstance(void)
	{
		if (instance == nullptr)
		{
			// 初回のみ動的確保
			instance = new T;
		}

		return instance;
	}

	/// <summary>
	/// インスタンスを破棄する
	/// </summary>
	static void DeleteInstance(void)
	{
		// 削除は動的確保している時のみ
		if (instance != nullptr)
		{
			delete instance;
			instance = nullptr;
		}
	}

private:
	static T* instance;
};
template<typename T>
T* Singleton<T>::instance = nullptr;

class Sample
	: public Singleton<Sample>
{
	// friend : privateへアクセス可能にする
	friend class Singleton<Sample>;

public:
	/// <summary>
	/// 出力
	/// </summary>
	/// <returns>出力結果</returns>
	inline std::string Output(void)
	{
		return "シングルトン";
	}
};

int main(void)
{
	Sample* sample = Sample::GetInstance();

	std::cout << sample->Output() << std::endl;

	Sample::DeleteInstance();

	return 0;
}
```

### C#
```C#:Singleton.cs
using System;

/// <summary>
/// シングルトン
/// 
/// ジェネリックで汎用性強化
/// where T : new()はインスタンス化の保証
/// </summary>
public class Singleton<T> where T : new()
{
    private static T instance;

    /// <summary>
	/// デフォルトコンストラクタ
    /// </summary>
    public Singleton() { }

    /// <summary>
	/// インスタンスを取得する
	/// </summary>
    public static T GetInstance
    {
        get
        {
            // 初回のみ動的確保
            return instance ??= new T();
        }
    }
}

// 派生クラス
public class Sample : Singleton<Sample>
{
    /// <summary>
    /// 出力
    /// </summary>
    public string Output
    {
        get
        {
            return "シングルトン";
        }
    }
}

public class Program
{
    static void Main()
    {
        // 動的確保
        Sample sample = Sample.GetInstance;

        // 出力
        Console.WriteLine(sample.Output);
    }
}
```
Next.js (Edge Runtime) の Route Handler テストでつまずいた話と、その解決策

テストを書いたことのあるプログラマーなら一度は「なんでテストが通らないんだ…？」と頭を抱えた経験があると思います。今回、私もまさにその状態に陥りました。それは、Next.js の Edge Runtime を使ったプロジェクトでのこと。Route Handler をテストしようとしたとき、あの忌々しい「`is not a function`」エラーに出くわしました。このエラーを克服するために試行錯誤した経験を、ここで共有します。同じ問題に悩む方の助けになれば幸いです。

---

## 問題に直面したときの状況

私が取り組んでいたのは、Next.js の Route Handler のテストでした。特に Edge Runtime を使う際には、Node.js 標準の `Response` と Next.js 独自の拡張 `Response` の間で競合が起こることがあります。その結果、`NextResponse.json()` を呼び出した瞬間に「`is not a function`」というエラーが発生してしまいました。

さらに、Jest を使ったテスト環境では、モジュールの読み込み順や `jest.mock()` の使い方次第で新たな問題が発生することがありました。このような細かいトラップがいくつも重なり、初めは手詰まり状態でした。

---

## 私が実践した解決策

いろいろ試してみた結果、以下の方法を組み合わせることで問題を解決できました。それぞれのアプローチを詳しく説明します。

### 1. Edge Runtime 対応のテスト環境を使用する

まず最初にやったのは、Jest のテスト環境を Edge Runtime に近づけることです。具体的には、`@edge-runtime/jest-environment` を `testEnvironment` に設定しました。これを導入することで、Next.js 独自の Web API 実装と Node.js のモック環境との競合を減らすことができました。

```json
// jest.config.js の例
{
  "testEnvironment": "@edge-runtime/jest-environment"
}
```

これだけで、「`is not a function`」エラーの発生頻度がかなり減りました。

---

### 2. 過剰なモックを減らす

テストをシンプルに保つことも重要でした。Edge Runtime 対応のテスト環境を使う場合、`Response.json()` のモックは不要です。むしろ余計なモックを追加すると、新たな問題を引き起こす原因になりました。テスト対象の範囲を明確にし、必要最低限のモックだけを使うことで、問題を切り分けやすくなりました。

---

### 3. ビジネスロジックと Route Handler の分離

私が抱えていた最大の問題は、テスト対象の範囲が広すぎたことでした。Route Handler の中にビジネスロジックを直接埋め込んでしまっていたため、テストが複雑化していたのです。

そこで、ビジネスロジックを独立したクラスや関数に切り出しました。これにより、ビジネスロジックそのものは単体テストでカバーし、Route Handler 側ではそのロジックをモックするだけで済むようになりました。

---

### 4. モックの読み込み順序を明確化

Jest で ES Modules を使う際には、モジュールの読み込み順が非常に重要です。`jest.mock()` を使う場合は、`import` 文よりも前に記述しなければモックが効きません。また、テスト間でモジュールキャッシュの影響を受けないよう、`jest.resetModules()` や `jest.isolateModules()` を活用しました。

---

### 5. パスエイリアスでモジュール管理を簡素化

プロジェクトの規模が大きくなると、相対パスが複雑になりがちです。そのため、`tsconfig.json` や `moduleNameMapper` を活用して、パスエイリアスを設定しました。これにより、モジュール間のパス管理がスムーズになり、テストコードの可読性も向上しました。

---

## 実際のコード例

具体例を挙げると、次のようにビジネスロジックと Route Handler のテストを分離しました。

### ビジネスロジックの単体テスト

```ts
// line-login-service.test.ts
describe("LineLoginService", () => {
  beforeEach(() => {
    global.fetch = jest.fn();
  });

  it("APIのURLが設定されていない場合", async () => {
    const service = new LineLoginService("");
    const result = await service.getLoginUrl();
    expect(result).toEqual({ error: "API URLが設定されていません" });
  });
});
```

### Route Handler のテスト（ビジネスロジックをモック）

```ts
// route.test.ts
jest.mock("@line-login-service", () => ({
  LineLoginService: jest.fn().mockImplementation(() => ({
    getLoginUrl: jest.fn().mockResolvedValue({ url: "https://line.login.url" }),
  })),
}));

describe("LINE Login Route Handler", () => {
  it("正常にURLを返す", async () => {
    const response = await GET();
    const body = await response.json();
    expect(body).toEqual({ url: "https://line.login.url" });
  });
});
```

---

## 最後に

今回の経験を通じて、「テストはシンプルであるべき」という基本的な考え方の大切さを改めて感じました。また、Edge Runtime のような特殊な環境でのテストは独特な課題が伴いますが、環境を整えるだけでも問題解決の糸口が見えてきます。

もし同じような問題に直面している方がいたら、この経験が参考になれば嬉しいです。そして、「まだこうした方が良いよ」というフィードバックがあれば、ぜひ教えてください！
DBのJOINE, LEFT JOIN, RIGHT JOINの覚えるポイント

実務や応用情報とかの問題でいつもDBのJOINE, LEFT JOIN, RIGHT JOINの違いが分からなくなるのでメモ📝

# INNER JOIN
## JOIN

![1000004675.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/a690dbc8-f94d-f914-aeb9-88cc7e8bca03.png)

- 結合できなかった行は返さない


# OUTER JOIN
## LEFT JOIN、RIGHT JOIN
![1000004676.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/513fd2e3-46c9-812c-3f3c-824050ebe050.png)

- 結合出来なかった行も無理矢理表示される
（NULLになることがある）
- LEFT JOINは、「主（左）」のテーブルに従う
- RIGHT JOINは、「従（右）」のテーブルを全て返す
# 参考サイト

https://qiita.com/Yinaura/items/3ab6fc49ae55f52e2d55

https://qiita.com/ngron/items/db4947fb0551f21321c0

# 追記
以下の動画も分かりやすかったです。

https://youtu.be/82qNsju8mQg?si=UhxoX3N-cVS1wIvM
IBM i のラインセスプログラムの必要ストレージ容量を調べたい

こちらのサイトに記載されています。

[ライセンス・プログラムのリリースとサイズ](https://www.ibm.com/docs/ja/i/7.5?topic=reference-licensed-program-releases-sizes)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/e3b7164c-f01a-1b84-5557-5c12c31f9e1f.png)
Home Assistantで日本のスマートメーターを統合：B-Route Smart Meter Integration

# Home Assistantで日本のスマートメーターを統合：B-Route Smart Meter Integration

**B-Route Smart Meter Integration**は、日本のスマートメーター（Bルート対応）からエネルギーデータを取得するためのHome Assistant用カスタムコンポーネントです。このプロジェクトを利用することで、エネルギー消費量を可視化し、スマートホームで効率的なエネルギー管理が可能になります。

---

## 特徴

このコンポーネントの主な特徴は以下の通りです：

- **リアルタイムデータ取得**：  
  以下のデータをBルートインターフェースを通じて取得します：
  - 瞬時電力（E7）
  - 瞬時電流（E8）
  - 瞬時電圧（E9）
  - 積算電力量（正方向：EA、逆方向：EB）

- **自動化された通信**：  
  PAN（Personal Area Network）認証とチャンネルスキャンを自動で行います。

- **簡単な設定**：  
  Home AssistantのUIから簡単に設定可能。

- **高頻度更新**：  
  データは10秒間隔で更新されます。

---

## 必要なもの

本コンポーネントを使用するには、以下が必要です：

1. **Bルート対応スマートメーター**  
   日本の電力会社から提供されるスマートメーターが対象です。

2. **Bルート認証情報**  
   電力会社から提供される「認証ID」と「認証パスワード」。 [TEPCO](https://www.tepco.co.jp/pg/consignment/liberalization/smartmeter-broute.html)

3. **USB-Wi-SUNアダプター**  
   例：BP35A1（動作確認済み）。

---

## インストール方法

以下の手順でセットアップを行います：

1. GitHubリポジトリから`b_route_meter`フォルダをダウンロードし、Home Assistantの`custom_components`ディレクトリにコピーします。
2. Home Assistantを再起動します。
3. UIで「B-Route Smart Meter」統合を追加します。
4. 設定画面で以下を入力します：
   - BルートID
   - Bルートパスワード
   - シリアルポート（デフォルト：/dev/ttyS0）

---

## 設定パラメータ

以下の設定をサポートしています：

| 項目         | 説明                  | 必須 | デフォルト値       |
| ------------ | ------------------- | ---- | ---------------- |
| route_b_id   | BルートID           | 必須 | なし             |
| route_b_pwd  | Bルートパスワード    | 必須 | なし             |
| serial_port  | シリアルポート       | 任意 | /dev/ttyS0       |

---

## 作成されるセンサー

インストールが完了すると、以下のセンサーエンティティが作成されます：

- `sensor.b_route_instantaneous_power`：瞬時電力（W単位）
- `sensor.b_route_instantaneous_current`：瞬時電流（A単位）
- `sensor.b_route_instantaneous_voltage`：瞬時電圧（V単位）
- `sensor.b_route_cumulative_forward`：正方向積算電力量（kWh単位）
- `sensor.b_route_cumulative_reverse`：逆方向積算電力量（kWh単位）

---

## トラブルシューティング

動作しない場合は以下を確認してください：

1. BルートIDおよびパスワードが正しく入力されているか。
2. シリアルポートの設定が正しいか。
3. 使用しているスマートメーターがBルート対応か。
4. Home Assistantのログにエラーが出ていないか。

---

このコンポーネントを活用することで、エネルギーデータをリアルタイムに監視し、効率的なエネルギー管理を実現できます。スマートホームでのエネルギー最適化に興味がある方はぜひお試しください！
DDD（ドメイン駆動設計）の復習part3

# ドメイン層
ドメインモデルを表現するもの（ドメインオブジェクト）
- 値オブジェクト
- エンティティ
- ドメインイベント

## 値オブジェクト
システム内で扱う値のルールをクラスとして表現したものです。
名前や年齢、ユーザー番号などシステムで扱われる値にはそれぞれ守るべきルールがありそれに違反する値はシステム内に存在させないようにする必要があります。
そのルールをクラス内に閉じ込め、再利用しやすくしたものが値オブジェクトです。

### 値オブジェクトの特徴
#### 完全コンストラクタにより安全性を保つ
インスタンスを生成した時点で完全な状態となるような初期化ロジックを組み、それ以降で値が書き変わらないようにします。
この考え方を完全コンストラクタといい、これによりオブジェクトが不正な状態で存在することがなくなります。
下の例だと、年齢オブジェクトはインスタンスが生成されたタイミングでバリデーションが実施され不正な値を弾き、さらにset関数がないため値の再設定によってさらなる不正値の設定を防ぎます。

``` typescript
export class Age {
  private readonly value: number;

  // コンストラクタでバリデーションを行ってから初期化
  private constructor(value: number) {
    if (value < 0 || value > 150) {
      throw new Error("年齢は 0 から 150 である必要があります。");
    }
    this.value = value;
  }

  // ファクトリーメソッドでインスタンスを作成
  public static create(value: number): Age {
    return new Age(value);
  }

  // 年齢を取得するゲッター
  public getValue(): number {
    return this.value;
  }

  // 等価性の判定
  public equals(other: Age): boolean {
    return this.value === other.value;
  }
}
```

#### 型を使ってコードを分かりやすくする
プリミティブ型のみだけで書いたコードは思わぬバグを生むことがあります。
例えば下記のように金額と数量を扱う場合に引数として渡す値が反対になってしまっていた場合、致命的なバグを発生させてしまいます。
``` typescript
amount(quantity:number, unitPrice:number){
    if(quantity > discountCreteria){
        return discountAmount(quantity, unitPrice)
    }

    return quantity * unitPrice
}
```

こういうことを防ぐために用途を限定した独自の「型」を使ってコードの意図を分かりやすくすべきです。

``` typescript
amount(quantity:Quantity, unitPrice:Money){
    if(quantity.isDiscountable()){
        return discountAmount(quantity, unitPrice)
    }

    return unitPrice.multiply(quantity.value())
}
```
number型の代わりにMoney型とQuantity型を使うことでコードの意図が具体的になり、引数の渡し間違いを防ぐ安全なプログラムになります。

#### ロジックの散在を防ぐことができる

### 値オブジェクトにする基準
上記の通り、値をプリミティブ型で扱わず値オブジェクトにすることでシステムにメリットがあることがわかりました。
ですが、値を片っ端から値オブジェクトにするのは骨が折れる作業ですし、本領を発揮しない場合もあります。
下記は値オブジェクトにすべき値の特徴です。

#### ビジネスルールがあるか
オブジェクトが独自のバリデーションルールやドメイン特有のビジネスロジック (メールアドレスの形式、電話番号の形式など) を必要とする場合、それらのデータの正確性が保たれます。
例えばめ

#### 再利用
システム内で頻出する値であれば
マルウェアがブロックされました “com.docker.vmnetd”にはマルウェアが含まれているため開けませんでした。この操作によるMacへの損害はありませんでした。

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


## 原因

https://forest.watch.impress.co.jp/docs/news/1653265.html


## やったこと
自分の場合はHomebrewを使ってDockerを入れていたので，普通にWebから落としてくるパターンだとおそらくちゃんと削除とかができないので

1. アクティビティモニタからDocker関連のプロセスは全て終了
1. `brew uninstall docker`
1. `brew install --cask docker`

色々と試したけど，多分これでイケた．


## 公式の発表

https://www.docker.com/ja-jp/blog/incident-update-docker-desktop-for-mac/