OmniAICreator/Qiita-1.07M huggingface dataset:
Swift @Observable ってなに？ SwiftUI

## `@Observable` とは

* マクロを利用して実現されている
* `@Observable`を追加したモデルの変更にビューが反応するようになる
* ビューのbodyで表示してないプロパティが更新されてもビューは更新されない？（以下の動画のドーナッツ屋の例で、orderが変わってもビューは更新されない）

https://developer.apple.com/videos/play/wwdc2023/10149/

## 背景

Apple公式のSwiftUIチュートリアルを最初からやっていたところ、突然現れたため、しっかり理解したいと思った。
https://developer.apple.com/tutorials/swiftui/handling-user-input

## あとがき

- SwiftUIはものすごく開発体験がよく感動すら覚えました。
- 一方、適切に利用するには深めの理解が必要そうだと思いました。
- チュートリアルで出た、 `@Environment`, `@State`, `@Binding`, `@Bindable` についてもしっかり理解しながら進めたいと思いました。
Comparing non-optional value of type 'String' to 'nil' always returns false

「Comparing non-optional value of type 'String' to 'nil' always returns false」というエラーメッセージは、非オプショナル型のStringをnilと比較しているため、常にfalseを返すという問題を指摘しています。Swiftでは、非オプショナル型の値はnilになることがないため、このような比較は意味がありません。以下のステップで問題を解決できます。

> コードの確認：

String型の変数がnilと比較されている箇所を探します。例えば、以下のようなコードが該当します。

~~~swift
let stringValue: String = "Hello"
if stringValue == nil {
    // このブロックは決して実行されない
}
~~~

> 比較の削除または修正：

もし変数がオプショナル型であるべき場合は、変数の宣言をオプショナル型に変更します。例えば、String?として宣言します。

~~~swift
let stringValue: String? = "Hello"
if stringValue == nil {
    // nilの場合に実行されるブロック
}
~~~

もし変数が非オプショナル型で正しい場合は、nilとの比較を削除します。代わりに、特定の条件や値との比較を検討してください。例えば、空の文字列との比較：

~~~swift
let stringValue: String = "Hello"
if stringValue == "" {
    // 文字列が空の場合に実行されるブロック
}
~~~

> ロジックの再評価：

この問題が発生する原因として、プログラムの設計段階で型の取り扱いに誤解があった可能性が考えられます。変数がnilになり得るのか、または常に値が保証されているのかを再評価し、コードの整合性を確保してください。
これらの対処方法により、無意味なnil比較を避け、より適切なプログラムの振る舞いを実現できます。

対応方法
~~~swift
extension String {
    static func isBlank(_ string:String?) -> Bool {
        return string == "" || string == nil
    }
}
~~~

呼び出しもと

~~~swift
    // var text:String = <# 値を取得　#>
    if String.isBlank(text) {
        // <# ここで作業　#>
    }　else {
        // <# ここで作業　#>
    }
~~~
上記のように対応することで、表題の課題は解決するでしょう
Automatically Adjusts Font requires using a Dynamic Type text style

~~~
Automatically Adjusts Font requires using a Dynamic Type text style
~~~

どういう対応すると良いですか

「Automatically Adjusts Font requires using a Dynamic Type text style」というメッセージは、フォントサイズをユーザーの設定に合わせて自動調整するためには、Dynamic Typeを使用する必要があることを示しています。Dynamic Typeを使用することで、アプリは異なるデバイスやユーザーのアクセシビリティ設定に適応できます。対処方法は以下の通りです。

> Dynamic Typeの利用：

UILabel、UIButton、UITextViewなどのテキストを表示するUIコンポーネントで、プロパティadjustsFontForContentSizeCategoryをtrueに設定します。これにより、ユーザーのデバイス設定に基づいてフォントサイズが自動調整されます。

> テキストスタイルの指定：

Interface Builderを使用する場合、各テキスト表示コンポーネントの属性インスペクターで、フォントセクションにある「Text Style」から適切なスタイル（例：Body、Headline、Captionなど）を選択します。

コードで設定する場合は、UIFont.preferredFont(forTextStyle:)を使用して、適切なテキストスタイルを指定します。例えば、ボディテキスト用のフォントを設定するには次のようにします：
~~~swift
label.font = UIFont.preferredFont(forTextStyle: .body)
~~~

> コンテンツサイズカテゴリの変更通知の監視：

アプリが実行中にフォントサイズが変更された場合、UIコンポーネントがそれに応じて更新されるように、UIContentSizeCategoryDidChangeNotificationの通知を監視することが必要になる場合があります。これは、特にカスタムビューを使用している場合に重要です。

以下の例は、UILabelのフォントをDynamic Typeに対応させる方法を示しています：

~~~swift
override func viewDidLoad() {
    super.viewDidLoad()
    
    let label = UILabel()
    label.adjustsFontForContentSizeCategory = true
    label.font = UIFont.preferredFont(forTextStyle: .body)
    view.addSubview(label)
}
~~~
この設定を行うことで、ユーザーがデバイスの設定でテキストサイズを変更しても、アプリのテキストが適切に調整されるようになります。
“View Controller“ is unreachable because it has no entry points, and no identifier for runtime access via -[UIStoryboard instantiateViewControllerWithIdentifier:].

~~~
“View Controller“ is unreachable because it has no entry points, and no identifier for runtime access via -[UIStoryboard instantiateViewControllerWithIdentifier:].
~~~

どういう対応すると良いですか

このエラーメッセージは、Storyboard内のViewControllerが他のコンポーネントからアクセスされない、またはStoryboard IDが設定されていないことを示しています。対処方法としては以下の手順を試してみてください。

> Storyboard IDの確認と設定：

XcodeでStoryboardファイルを開きます。
問題のあるViewControllerを選択します。
右側の属性インスペクターパネルで、"Identity Inspector" タブを開きます。
"Storyboard ID"フィールドに、一意のIDを入力します。このIDを使ってプログラムからインスタンスを生成できます。

> Entry Pointの確認：

ViewControllerがアプリの起動時に最初に表示されるべきものであれば、そのViewControllerに対して「Is Initial View Controller」オプションを有効にします。
これは、StoryboardのCanvasで選択したViewControllerの上部にある小さな矢印をクリックして設定できます。

> プログラムからの呼び出しの確認：

もしプログラムコードからViewControllerをインスタンス化する場合は、Storyboard IDを用いて正しく呼び出されているか確認してください。例えば、以下のようなコードを使用します。

~~~swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewControllerID")
~~~

これらのステップを実行後も問題が解決しない場合は、具体的なコードやエラーメッセージを元にさらに調査する必要があります。
WPFでフォント一覧

# C#

```dev.bat
@echo off
path %path%;C:\Windows\Microsoft.NET\Framework64\v4.0.30319
prompt $e[33m$p$g$e[m
cmd
```

```wpf.rsp
# csc @wpf.rsp foo.cs

/r:System.Xaml.dll
/r:WPF\PresentationCore.dll
/r:WPF\PresentationFramework.dll
/r:WPF\WindowsBase.dll
```

```fontlist.cs
// csc /t:winexe @wpf.rsp fontlist.cs
using System;
using System.Windows;
using System.Windows.Controls;
using Media = System.Windows.Media;

class MainWnd : Window {
	public MainWnd() {
		var sp = new StackPanel();

		var ffs = System.Drawing.FontFamily.Families;
		int i = 0;
		foreach (var ff in ffs) {
			var tblk = new TextBlock();
			tblk.FontFamily = new Media.FontFamily(ff.Name);
			tblk.FontSize = 20;
			tblk.Text = string.Format(
				"{0}: 012 ABC 漢字 {1}", ++i, ff.Name);
			sp.Children.Add(tblk);
		}

		var sv = new ScrollViewer();
		sv.Content = sp;
		Content = sv;
	}
}

class Program {
	[STAThread]
	static void Main() {
		var wnd = new MainWnd();
		wnd.ShowDialog();
	}
}
```

# PowerShell

UTF-8 (BOM付き)で保存。

```fontlist.ps1
# powershell -ExecutionPolicy RemoteSigned ./fontlist.ps1

Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.Drawing

$sp = New-Object Windows.Controls.StackPanel

$ffs = [Drawing.FontFamily]::Families
$i = 0
foreach ($ff in $ffs) {
	$tblk = New-Object Windows.Controls.TextBlock
	$tblk.FontFamily =
		New-Object Windows.Media.FontFamily($ff.Name)
	$tblk.FontSize = 20
	$tblk.Text = [string]::Format(
		"{0}: 012 ABC 漢字 {1}", ++$i, $ff.Name)
	[void] $sp.Children.Add($tblk)
}

$sv = New-Object Windows.Controls.ScrollViewer
$sv.Content = $sp
$wnd = New-Object Windows.Window
$wnd.Content = $sv
[void] $wnd.ShowDialog()
```
備忘録(Python)

# ボタンが上手くいかない！
ボタンを押して、入力してもらった値を適当な変数に保存しときたい
getしたやつはstrだからint(ボタン.get())したいのに
~~~
ValueError: invalid literal for int() with base 10: ''
~~~
**valueError**になる。

:::note
引数を使うときはlambdaを入れよう！
:::

~~~use_lambda.py
def ButtonClick(Num):
  a = edit_box1.get()
  print(a)
  Num = int(a)

root = tk.Tk()

root.geometry = ("600*300")
root.title("ラーメン屋")
label = tk.Label (root,text="人数の入力")
label.place(x=20,y=20)
edit_box1 = tk.Entry(width = 20)
edit_box1.place(x = 50 , y = 40)

Num_people = 0
button1 = tk.Button(root,text = "チェック",command=lambda:ButtonClick(Num_people))
button1.place(x= 120,y=60)
~~~

button1を定義してるところで、command=のあとに
**lambda:**　を入れるだけで解決した。

参考：
[Python] Tkinterのボタンが押された時に引数付き関数を呼び出したい。
(https://www.earthlink.co.jp/engineerblog/technology-engineerblog/7744/)
【ABC330】FortranでA,B,C問題

## 目次
  - [A - Counting Passes](#a---counting-passes)
  - [B - Minimize Abs 1](#b---minimize-abs-1)
  - [C - Minimize Abs 2](#c---minimize-abs-2)

## A - Counting Passes
### 問題
N 人が試験を受けました。それぞれの点数は $A_i$ 点です。
試験では L 点以上を取った人が合格になります。
N 人中何人が合格したかを求めます。

>**制約**
>1. 入力は全て整数
>2. $1 ≤ N ≤ 100$ 
>3. $1 ≤ L ≤ 1000$
>4. $0 ≤ A_i ≤ 1000$

詳細はこちらです。

https://atcoder.jp/contests/abc330/tasks/abc330_a

### 解説
N人全員の点数を調べ、合格した人の合計を求めます。

### プログラム例
```Fortran
program abc330a
    !N   :受験者数
    !A(N):N人分の試験の点数
    !L   :合格点
    !cnt :合格者数
    implicit none
    integer i, N, L, cnt
    integer, allocatable::A(:)

    !入力
    read (*, *) N, L
    allocate (A(N))
    read (*, *) A(1:N)

    !カウント
    cnt = 0
    do i = 1, N
        if (A(i) >= L) cnt = cnt + 1
    end do

    !結果の出力
    write (*, *) cnt
end program abc330a
```



## B - Minimize Abs 1
### 問題
N 個の整数 $A_1 ,A_2,…,A_N$ と整数L,Rが与えられます。 
$i =1,2...N$　の時以下の条件を満たす整数$X_i$を求めます。

>**条件**
>1. $L≤ X_i ≤ R$
>2. L 以上、R以下であるどの整数Yでも$|X_i - A_i| ≤ |Y_i - A_i| $を満たす。
>3. A_1 ,A_2 ,…,A_N がすべて等しいということはない

>**制約**
>1. $L ≤ N ≤ ２*10^5$
>2. $1 ≤ L ≤ R ≤ 10^9$
>3. $1 ≤ A_i ≤ 10^9$
>4. 入力は全て整数

詳細はこちらです。

https://atcoder.jp/contests/abc330/tasks/abc330_b


### 解説
条件を満たす整数$X_i$のパターンは、**$A(i),L,R$** の３パターンに分けられます。
条件の切り分けを行い、回答を出力します。

### プログラム例
```Fortran
program abc330b
    !N   :整数列Aの長さ
    !L,R :整数L、R
    !A(N):整数列
    implicit none
    integer(16) N, L, R, i
    integer(16), allocatable :: A(:)

    !入力
    read (*, *) N, L, R
    allocate (A(N))
    read (*, *) A

    !場合分けして出力
    do i = 1, N
        if (A(i) >= L .and. A(i) < R) then !L以上R未満
            write (*, '(i0,1x)', advance='no') A(i)
        elseif (A(i) < L) then !L未満
            write (*, '(i0,1x)', advance='no') L
        elseif (A(i) >= R) then !R以上
            write (*, '(i0,1x)', advance='no') R
        end if
    end do
end program abc330b
```



## C - Minimize Abs 2
### 問題
正整数 D が与えられます。
非負整数 x,y に対する $∣x^2+y^2−D∣$ の最小値を求めます

>1. $1≤D≤2×10^{12}$
>2. 入力は全て整数


詳細はこちらです。

https://atcoder.jp/contests/abc330/tasks/abc330_c


### 解説
全探索を行い最小値を見つけます。
探索範囲はyを十分大きい数($2×10^6$)から１ずつ小さく、xは０から１ずつ大きくしていき行います。



### プログラム例
```Fortran
program abc330c
    !D    ：正整数D
    !x    ：非負整数x
    !y    ：非負整数y
    implicit none
    integer(8) x, y, ans, D

    !入力
    read (*, *) D

    !最小値の検索
    ans = D
    y = 2*10**6
    do x = 0, 2*10**6
        do
            if (y > 0 .and. x*x + y*y > D) then
                y = y - 1
            else
                exit
            end if
        end do
        ans = min(ans, abs(x*x + y*y - D))
        ans = min(ans, abs(x*x + (y + 1)*(y + 1) - D))
    end do

    !出力
    write (*, *) ans
end program abc330c
```


## 感想
- 繁忙期で忙しく、参加する暇がありませんでした...
- 年度を跨いでも忙しさは改善されなかったので、今後はフロー図省略して更新します。
[Google Photos Library API] JavaでGoogleフォトのアルバムにメディアアイテム(写真や動画)を追加する

Google Photos Library API(Java)を使用して、
Googleフォトのアルバムにメディアアイテム(写真や動画)を追加する方法
についてご紹介します。

アルバムに追加するメディアアイテムは、Photos Library APIで
アップロードしたメディアアイテムのみになります。

メディアアイテムの追加方法は
[⧉[Google Photos Library API] JavaでGoogleフォトのメディアアイテム(写真や動画)を追加・更新する](https://qiita.com/doran/items/fd6ea924f8ce8071ce8c)
を参照ください。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う](https://qiita.com/doran/items/8695e6007765ab5b382c)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[メディアアイテムを追加](#1-メディアアイテムを追加)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|

## 1. メディアアイテムを追加
指定したアルバムにメディアアイテム(写真や動画)を追加します。

### 1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
https://www.googleapis.com/auth/photoslibrary
https://www.googleapis.com/auth/photoslibrary.appendonly
https://www.googleapis.com/auth/photoslibrary.sharing
```
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う(2.2. PhotosLibraryClientインスタンスを取得)](https://qiita.com/doran/items/8695e6007765ab5b382c#22-photoslibraryclientインスタンスを取得)
でスコープを指定してください。

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(PhotosLibraryClient client = getPhotosLibraryClient()){
        BatchAddMediaItemsToAlbumResponse response = client.batchAddMediaItemsToAlbum("アルバムID",Arrays.asList("メディアアイテムID"));
        System.out.println(response);
    }
}
```
#### 1.2.1. HTTPリクエスト
POST:　https:\//photoslibrary.googleapis.com/v1/albums/{アルバムID}:batchAddMediaItems
が実行されます。

#### 1.2.2. クエリパラメータ
クエリパラメータはありません。

### 1.3. レスポンスの内容
成功した場合は何も返しません。
失敗した場合は例外を出力します。

<br>
<br>
おしまい。。
SAP Discovery Centerで学ぼう

以前こちらの記事でSAP Tutorialsを取り上げたのですが、

https://qiita.com/Nel_SAP_Basis/items/ffa712a99b619fe2243d

SAP Discovery Center なる学習用サイトも存在していたようです。

https://discovery-center.cloud.sap/protected/index.html

![スクリーンショット 2024-04-20 19.04.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/3aeda274-297c-3618-4484-5cdfd6228458.png)

Tutorilsと同様にMissionsが存在し、中身もかなり似たような感じになっています。

![スクリーンショット 2024-04-20 19.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/46afc88f-25e9-07a1-0eea-b80d77afd327.png)

では、SAP Discovery CenterとSAP Tutorialsとは何が違うのか？
よくわからなかったので、ChatGPTさんに聞いてみたところ、以下の回答をいただきました。

「SAP Discovery Centerは、実際のビジネスシナリオの実装を支援し、プロジェクトの管理ツールと専門家のリソースを提供することに重点を置いています。対照的に、SAP Tutorialsは、SAPの製品を使用する方法を一から学ぶためのリソースとして設計されており、特定のタスクや機能の詳細なガイドを提供します。」

![スクリーンショット 2024-04-20 18.35.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/f1d320a8-c1ff-b105-de20-04b830a97df3.png)

確かによく見ると、ビジネスユースと思われるMissionsが用意されており、

![スクリーンショット 2024-04-20 19.19.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/b504723c-bd8a-d853-b7f5-4a22a04aa2a8.png)

わざわざ「Try for free」と書かれているMissionsがあるところを見ると、SAP Discovery Centerの方は、実際の企業で利用するSAPシステムに対しての導入ガイド的な位置付けなのかと思われます。考えてみたらSAP Tutorialsの手順は、Trialアカウントで試せるようになっていました。

![スクリーンショット 2024-04-20 19.19.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/14070e5f-44f3-a481-7197-fafc1f60655f.png)

結構面白そうなMissionsが沢山ありそうです。こちらはSAP S/4HANAとMicrosoft TeamsをSAP BTPを介して連携させるMissionになります。
![スクリーンショット 2024-04-20 19.26.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/515b4597-1fef-a2e2-a5e7-b417a8167e08.png)

発注者が発注書の承認をマネージャに依頼→マネージャがSAPにログイン→該当の発注書を表示→内容を確認→承認。みたいなプロセスが、発注者が発注書の承認をSAPから依頼、マネージャがTeamsの通知を受け取り、Teamsから内容を確認して承認。と、導入したら発注承認処理が非常に効率的になりそうです。

画像引用元：https://discovery-center.cloud.sap/protected/index.html#/missiondetail/4164/4408/
![スクリーンショット 2024-04-20 19.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/14c45a58-6e73-821b-2395-b87ccd7dd023.png)

今回の記事は以上になります。お疲れ様でした。
【TypeScript】RDBを手軽にいい感じに扱う @databases

`@databases` はTypeScriptのRDBクライアントライブラリ。ORMではなく、SQLを直接書く又はクエリビルダーを使う系のライブラリ。Postgres、MySQL、SQLiteなどで使える。

これは私が他のRDBクライアントライブラリに対して「なんでこうしないんだよ」と思っていた設計が全部盛り込まれていて、とても使い心地が良い。

https://www.atdatabases.org/

# 使い方概要
このライブラリにはSQLを直接書く方法とクエリビルダーを使う方法の2種類の使い方がある。2つの長所と短所は以下。

- SQL直書き
    - ✅どんなクエリでもかけるのでRDBの機能をフルに活用できる
    - ❌TypeScriptの型がつかない
- クエリビルダー
    - ✅TypeScriptの型がつく
    - ❌扱えるクエリは限られる

## SQL直書き

以下がコード例。

```typescript
import createConnectionPool, { sql } from '@databases/mysql';


const db = createConnectionPool(
  'mysql://root@db/codetest',
);

await db.tx(async db => {
    await db.query(sql`
      INSERT INTO transactions (user_id, amount, description)
      SELECT ${request.body.user_id}, ${request.body.amount}, ${request.body.description}
      WHERE 0 = (
        SELECT IF(SUM(amount) + ${request.body.amount} > 1000, 1, 0)
        FROM transactions WHERE user_id = ${request.body.user_id}
      )
    `);
});
```

コードの書き方の特徴を以下に示す。

### async await
ライブラリ全体で非同期処理に`async`関数が使わている。まあ今時コールバックなんて時代錯誤だから当然だが、意外といろんなライブラリでまだ蔓延ってるからね。

### クエリへの値埋め込み
クエリに値を埋め込むのに JavaScript の機能 [Tagged Template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) を用いている。これによって他のライブラリだと

```javascript
db.query("UPDATE animals SET name = ? WHERE id = ?", [name, id])
```

のように書かなければならないところ、

```javascript
db.query(sql`UPDATE animals SET name = ${name} WHERE id = ${id}`)
```

のようにとてもスマートで読みやすく記述できている。変数を埋め込んだ部分はSQLインジェクションされないようちゃんとエスケープされる。普段あまり使われない Tagged Template の教科書に載せたい活用方法って感じ。

### トランザクション
トランザクションを記述するには処理をラムダ式で書いて`db.tx()`関数の中に渡す。`COMMIT`や`ROLLBACK`を明示的に呼ぶ必要は無し、ラムダ式が普通に帰れば自動で`COMMIT`され、例外が投げられれば自動で`ROLLBACK`される。

## クエリビルダー
クエリビルダーを使うことで、扱えるクエリが単純なものに限られるのと引き換えに、クエリを型安全に書くことができる。

まずは以下のようにCLIを使い、データベースからテーブルのスキーマを取得してTypeScriptの型ファイルを生成する。

```shell
npx @databases/mysql-schema-cli \
  --database mysql://test-user:password@localhost:3306/ \
  --schemaName test-db \
  --directory src/__generated__
```

生成したファイルを使用してクエリビルダーを構築することで、型付きでクエリを呼び出せる。

```typescript:src/main.ts
import createConnectionPool from '@databases/mysql';
import tables, {gt} from '@databases/mysql-typed';
import DatabaseSchema, {serializeValue} from './__generated__';

const db = createConnectionPool();

// You can list whatever tables you actually have here:
const {users, posts} = tables<DatabaseSchema>({
  serializeValue,
});

await users(db).insert({email: 'me@example.com', favorite_color: 'red'});
const users = users(db).find({favorite_color: 'blue'});
await posts(db).delete({updated_at: gt(new Date(Date.now() - 24 * 60 * 60 * 1000))});
```

最後の3行のクエリする関数は各引数、戻り値ともにデータベースのスキーマに応じた型が付くのでカラム名を間違えるなどのコーディングミスを減らせる。

# 注意点
まだマイナーなプロジェクトなので粗が見える部分がある。（私が立てたissueだが）[型の宣言がおかしい](https://github.com/ForbesLindesay/atdatabases/issues/321)ことがあったり、データベースの切断手続きをちゃんとやってないのか、MySQL側で「Aborted connection」みたいなログがたくさん出たりした（クエリ自体はちゃんと処理されている）。
【Lambda】手動実行する際、意図せず2重実行される事象について

## 発生事象
EC2インスタンスのイメージバックアップを取得するLambda関数をLambda コンソールの [テスト] 画面にて関数のテストを実行した際に、1 度のテスト実行操作に対して関数が 2 回呼び出されました。
⇒バックアップ処理自体は問題なく完了したが、CloudWatchアラームにてエラーとして検知されてしまいました。

同時刻に2つのログストリームが生成され、片方のログは成功、もう片方は失敗という内容でした

■Lambda実行時、CloudWatchに出力されたログ
![Lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691986/42606099-c306-b525-e53e-33f86025ab8e.png)

Lambdaの仕様として、同期呼び出しとしてLambdaを実行すれば多重実行を防げるといったような情報も確認しましたが、同期実行（CloudShellからの実行）でも2重実行されてしまいました。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-sync.html

https://qiita.com/is_ryo/items/009220083e179272cbda

## 原因
本事象をAWSに問い合わせたところ、以下の回答がありました。
>・Lambda コンソールの [テスト] 画面にてテストを実行した場合、基本的に関数は 1 度呼び出される
・ただし、利用しているブラウザから Lambda サービスまでのネットワーク経路上にあるプロキシサーバーなどに起因して2重実行される場合がある

つまり、<font color="Red">接続時のネットワーク環境に起因して2重実行されてしまうことがある</font>とのことでした。
本事象は社内ネットワークからAWSコンソール画面に接続し、Lambdaを実行していた時に発生していた事象だったので、試しに別のネットワーク環境からLambdaを実行してみたところ、2重実行されず一度の処理で実行が完了しました。
また、よくある構成のEventBridge 経由で呼び出される Lambda の場合は、ネットワーク環境に起因して重複して起動されることはないとのことでした。

## 教訓
Lambdaを手動実行する際は、端末が接続しているネットワークに起因して本事象がおこる可能性があることを考慮しましょう。
PHP Trait (トレイト) について

# Trait (トレイト)

- __トレイトの目的__ :  PHP では、複数のクラスで同じメソッドを共有するためにトレイトが使用されます。
これは、PHP が単一継承しかサポートしていないためめ、複数のクラスで同じメソッドを再利用するための解決策でもあります。

- __トレイトの制限__ :  トレイトはインスタンス化できません。つまり、トレイト自体はオブジェクトを作成することはできません。
また、トレイトはクラスのように継承することもできません。

- __トレイトの優先順位__ :  クラス内で同じ名前のメソッドが存在する場合、クラスのメソッドが優先されます。これは、クラスがトレイトから継承したメソッドを上書き（override）することができるためです。

- __トレイトの衝突__ :  ２つのトレイトが同じ名前のメソッドを持っていて、それらのトレイトが同じクラスで使用される場合、PHPはエラーをスローします。
これを解決するためには、`insteadof` キーワードを使用して、どのトレイトのメソッドを使用するかを明示的に指定する必要があります。

- トレイトを持ってくるには `use` キーワードを使う。

__●__ Trait (トレイト) 実装例

```php:sample.php
<?php

trait ProductTrait
{
    public function getProduct()
    {
        echo 'プロダクト';
    }
}

trait NewsTrait
{
    public function getNews()
    {
        echo 'ニュース';
    }
}

class Product
{
    use ProductTrait;
    use NewsTrait;

    public function getInformation()
    {
        echo 'クラスです';
    }

    // overrideも可能
    public function getNews()
    {
        echo 'クラスのニュースです';
    }
}

$product = new Product(); // インスタンス化

$product->getInformation();
echo '<br>';
$product->getProduct();
echo '<br>';
$product->getNews();
echo '<br>';
```
typst フォント まとめ

## はじめに
typst で用いることができる日本語フォントをまとめました．

## 結果
以下の通り．
一部のフォントでは，対応する日本語フォントが存在しないため，デフォルトのフォントで出力されている．

![fonts1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642842/a80a6baf-efb9-a491-39d6-f5182a2fc37e.png)

![fonts2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642842/82b1f490-23db-50ea-cc97-8222eec68db3.png)

![fonts3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642842/d4e14cfa-8da6-f237-d7b7-0b27effa8f96.png)

![fonts4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642842/47ace961-5a8d-3904-d794-8e1351b52ad4.png)

![fonts5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642842/87485561-a112-0aa5-d878-01e16256cf2e.png)

![fonts6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642842/5eb121cb-3992-de37-d124-bb38d30fe325.png)

## 方法
方法についても記載しておく．
typst をインストールしたのち，コマンドラインから以下を実行してフォント一覧を得る．
```bash
typst fonts > fonts.txt
```
python で適当にフォーマットし，jsonファイルにする．
なお，エンコーディングを指定しているのは，Windows 環境では cp932 云々のエラーがごちゃごちゃぬかしたため．
```Python: format.py
import json

def txt_to_json(input_file, output_file, encoding='utf-8'):
    # テキストファイルを読み込み
    with open(input_file, 'r', encoding=encoding) as f:
        lines = f.readlines()

    # JSON形式に整形
    entries = [{"name": line.strip()} for line in lines]

    # JSONファイルに書き込み
    with open(output_file, 'w', encoding=encoding) as f:
        json.dump({"entries": entries}, f, indent=4, ensure_ascii=False)

# 入力ファイルと出力ファイルを指定して実行
input_file = "fonts.txt"
output_file = "fonts.json"
txt_to_json(input_file, output_file, encoding='utf-8')  # エンコーディングを適切に指定する
```
最後に次の typ ファイルをコンパイルすれば，ok.
fonts.typ のコードは 参考文献[1] を参考にさせていただきました．ありがとうございます．
```typ: fonts.typ
== フォント
#let text_example = "Hello World! 木曾路はすべて山の中である。"
#for entry in json("fonts.json").at("entries") {
  text(
    font:entry.name,
    [- #entry.name : #text_example]
    )
}
```
今回は png 形式で出力する．
```bash
typst compile fonts.typ fonts{n}.png
```



## 参考文献
* [1] [Typst 備忘録 -フォント一覧と日本語対応フォント-](https://powercore.hatenablog.com/entry/2023/12/18/093249)
* [2] [Typst： いい感じのLaTeXの代替](http://www-het.phys.sci.osaka-u.ac.jp/~yamaguch/j/typst.html)
Fedora39でminikube - ServiceをDeployする(1)

[Fedora39でminikube - pod確認(1)](https://qiita.com/intrajp/items/297080b3dfdd56305015)からの続きです。

```BASH
@fedora:~$ kubectl_m create deployment hello-minikube --image=kicbase/echo-server:1.0
deployment.apps/hello-minikube created
@fedora:~$ kubectl_m expose deployment hello-minikube --type=NodePort --port=8080
service/hello-minikube exposed
```

確認します。

```BASH
@fedora:~$ kubectl_m get services
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
hello-minikube   NodePort    10.97.204.75   <none>        8080:32147/TCP   75s
kubernetes       ClusterIP   10.96.0.1      <none>        443/TCP          13d
```

ブラウザで確認します。

```BASH
@fedora:~$ minikube service hello-minikube
|-----------|----------------|-------------|-----------------------------|
| NAMESPACE |      NAME      | TARGET PORT |             URL             |
|-----------|----------------|-------------|-----------------------------|
| default   | hello-minikube |        8080 | http://192.168.59.100:32147 |
|-----------|----------------|-------------|-----------------------------|
🎉  デフォルトブラウザーで default/hello-minikube サービスを開いています...
```

ブラウザで開くと、この様に表示されます。

```
Request served by hello-minikube-7f54cff968-xhftg

HTTP/1.1 GET /

Host: 192.168.59.100:32147
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0
```

ポートフォーワードもできます。

```
@fedora:~$ kubectl_m port-forward service/hello-minikube 7080:8080
Forwarding from 127.0.0.1:7080 -> 8080
Forwarding from [::1]:7080 -> 8080
Handling connection for 7080
```

ブラウザで http://localhost:7080/ を開くと、この様に表示されます。

```
Request served by hello-minikube-7f54cff968-xhftg

HTTP/1.1 GET /

Host: localhost:7080
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0
```

(参考)[minikube start](https://minikube.sigs.k8s.io/docs/start/)

[Fedora39でminikube - LoadBalancerをDeployする(1)](https://qiita.com/intrajp/items/b0234e7a1c040e8bca55)につづく。
【Git】Gitにパスを通す。（MacOS / zsh）

今回はGitに環境変数パスを通すやり方についての備忘録です。

## 私のGit使用環境
■私の開発環境
PC:MacOS
使用シェル:zsh
<br>

■Gitの使用環境は大きく分けて2つあります。
- 1: 元々MacOSにすでにインストールされている"Git"
- 2: Homebrewという"macOS用のパッケージマネージャーでインストールしたGit"(私の現在の環境です)

元々「1:」のGit環境でGitを使っていました。
ですが『効率が悪い...』と思ったことがあって、途中で「2:」の環境に切り替えました。

![homebrew.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338535/be3e8ab3-3093-5aee-5488-a5eaca3ce7b7.png)
※現在の環境


## 現在の環境のメリット
- gitのアップデートが楽（Homebrewのコマンド1行だけで済む。）
- Homebrewが色々と便利。
- git commit時にGitエディタが開かなかったが、パスを通したことにより自動で開くようになった(Vscode上で、シェルコマンドを毎回打ってパスを通していた)




## ⭕️やり方
以下が手順です！

1:自分のOSのシェルを確認する。
2:Homebrewをインストール。
3:HomebrewでGitをインストール。
4:「zshrcと、viエディタ」で、どのGitを使うかを指定するためにパスを通す。
5:先ほど作成した「zshrcファイル」をPCに反映させましょう。
6:インストールされたGitを確認する。

## 1:自分のOSのシェルを確認する。

- シェルって？

詳しく解説していただいてるサイト様が下記になります。
ありがとうございます...。

https://mykii.blog/what-is-shell-bash-and-zsh/



⬇︎
では、シェルの正体が分かったところで、自分の環境下のシェルを確認しておきましょう。
ターミナルで下記コマンドを入力します。
```言語:自分のシェルを確認する
echo $SHELL
```


上記コマンドecho $SHELLを使用すると
**/bin/zsh**
と表示されました。
どうやら私は「zshシェル」を使っているようです。


## 2:Homebrewをインストール。
Homebrewをインストールしましょう。
インストールは、こちらのユーザー様を参考にさせていただきました。

https://zenn.dev/inablog/articles/5e790c9fbdad20


## 3:HomebrewでGitをインストール。
①Homebrewがインストールされたら早速「Homebrew用のGit」をインストールしましょう。
```言語:「Homebrew用のGit」をインストール
brew install git
```
<br>

②次に「Gitがちゃんとインストールされているか確認」します。
```言語:Gitがちゃんとインストールされているか確認
which git
```
/usr/local/bin/git
と表示されました。
しっかりインストールされているようです。



## 4:「zshrcと、viエディタ」で、どのGitを使うかを指定するためにパスを通す。
ここから「シェルのランコマンド(zshrc)」を使ってパスを通します。
シェルを通す意味は「使うGitのパス」をシェルでプログラムに教えるためです。
・zshrc、viエディタについては下記のサイト様で解説されています。

https://note.com/standenglish/n/ne9825624fe93


・ここで先ほど確認したシェルが活躍します。私の使用しているシェルは「zsh」です。
**「zshrc」でパスを追加します。**
```言語:ターミナルで下記をコマンド
vi ~/.zshrc
```
⬇︎
するとこんな感じの画面になります。
これがViエディタです。
（既にGitのパスを通しているので、パスがもう書かれています。）
![スクリーンショット 2024-04-20 18.22.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338535/af5e5579-82a2-469d-dcdf-958c598ac37d.png)
⬇︎
```言語:Viエディタで下記コマンドを入力。
# >>> git >>>
# パスを通す
export PATH=/usr/local/bin/git:$PATH
# <<< git <<<
```
<br>

■Viエディタの入力方法
①【インサートモードで入力する】
手元のキーボードの「i」キーを押すとインサートモードになり、コードの入力ができるようになります。
「INSERT」と表示されています。
![スクリーンショット 2024-04-20 18.31.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338535/cafc9243-aa37-d3e8-5e58-ffcbae9556d9.png)
<br>

②【インサートモードを終了する。】
手元のキーボードの「esc」キーを押すとインサートモードが解除されます。
<br>

③【保存してViエディタを終了する。】
キーボードで「:wq」コマンドを打ち、キーボードのENTERキーを押すと保存してViエディタを終了します。
![スクリーンショット 2024-04-20 18.34.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338535/7eaec4ae-73fe-cccd-ed6b-1b422344929e.png)



## 5:先ほど作成した「zshrcファイル」をPCに反映させましょう。
```言語:# zshの場合
%source ~/.zshrc
```
これでzshrcファイルがPCに反映されています。


## 6:インストールされたGitを確認する。
```言語:インストールされたGitを確認する
git --version
```
上記コマンドを打つと
**git version 2.33.0**
が表示され確認できました。


## パス通し完了。
これでパス通しが完了です。
試しに
- gitのアップデートなどをしてみる。
- git commitしてみる。（パスを通したことにより自動で開くようになっていると思います。)


それでは今回はここまで。
ありがとうございました。
isRequiredでフォームの入力を必須にすると、未入力の場合デフォルトのエラーメッセージが出力される。

# はじめに
React×TypeScript×ChakuraUIでアプリを作成中です。
入力必須フォームを作成する際にisRequiredを使ったのですが、気づいたことがあったのでメモします。
# 問題
**フォームが未入力の場合、「ログインIDの入力は必須です」のエラーメッセージを出したいのに、「このフィールドを入力してください」のエラーメッセージが出てしまいます。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3675500/6313c711-f882-8c09-d1f5-2988239a639f.png)

入力フォームの実装を抜粋しました。
```tsx:tsx
 <Box p={3}>
          <FormControl isInvalid={!!errors.loginID} isRequired>
            <FormLabel>好きな英単語</FormLabel>
            <Input
              data-testid="login-id"
              placeholder=" "
              {...register("loginID", { pattern: /^[A-Za-z]+$/i })}
            />
            <FormErrorMessage>
              {errors.loginID && "英字で入力してください"}
            </FormErrorMessage>
          </FormControl>
        </Box>
```

# 解決方法
**isRequiredを消去したら自分でカスタムしたエラーメッセージが表示できるようになりました。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3675500/7947d41f-6ed9-ed88-c3eb-b308164a2565.png)

```tsx:tsx
<Box p={3}>
          <FormControl isInvalid={!!errors.loginID}>
            <FormLabel>好きな英単語</FormLabel>
            <Input
              data-testid="login-id"
              placeholder=" "
              {...register("loginID", {
                required: "ログインIDの入力は必須です",
                pattern: {
                  value: /^[A-Za-z]+$/i,
                  message: "英字で入力してください",
                },
              })}
            />
            <FormErrorMessage>
              {errors.loginID && errors.loginID.message}
            </FormErrorMessage>
          </FormControl>
        </Box>
```

# おわりに
**isRequiredプロパティは、フォームの入力を指定する＋未入力時にデフォルトで「このフィールドを入力してください」のエラーメッセージを出力してくれるようです。**

https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/required
GitLabからGitHubへリモートリポジトリの向き先を変更する方法

## はじめに

個人開発でGitLabで管理していたプロジェクトをGithubに移行したく、方法を調べたので備忘録として記事に残します。この記事では、既にGitLabに設定されているリモートリポジトリの向き先をGitHubに変更する手順を紹介します。

## 1. 現在のリモートリポジトリを確認

まず、現在設定されているリモートリポジトリの状態を確認します。これは `git remote -v` コマンドで行います。このコマンドは、設定されているリモートリポジトリの名前とURLを表示します。

```bash
git remote -v
```

出力例：

```
origin  https://gitlab.com/username/project.git (fetch)
origin  https://gitlab.com/username/project.git (push)
```

## 2. リモートリポジトリのURLを変更

次に、リモートリポジトリのURLをGitHubのものに変更します。これには `git remote set-url` コマンドを使用します。`origin` という名前のリモートリポジトリのURLを新しいものに置き換えます。

```bash
git remote set-url origin https://github.com/your-username/your-repository.git
```

このコマンドを実行後、再び `git remote -v` コマンドでURLが正しく変更されたことを確認します。

出力例：

```
origin  https://github.com/your-username/your-repository.git (fetch)
origin  https://github.com/your-username/your-repository.git (push)
```

## 3. 新しいリモートリポジトリにプッシュ

最後に、新しいリモートリポジトリに対してコードをプッシュして、変更が正しく反映されているかを確認します。

```bash
git push origin master
```

もし `master` ブランチがなく、`main` ブランチを使用している場合は、`master` の部分を `main` に置き換えてください。

## まとめ

この手順により、GitLabからGitHubにリモートリポジトリの向き先を簡単に変更することができます。これにより、リポジトリの管理をより柔軟に行うことが可能になります。
【Transformer の位置情報 5 選】APE と  Relative PE と RoPE と ALiBi と NoPE

## Transformer の位置情報

Transformer は順序に依存しない自己注意機構を採用しているため、入力シーケンス内の各トークンの位置情報を明示的にモデルに入れ込む必要があります。

そして、この位置情報の入れ込み方にいくつかバリエーションがあります。
- Absolute Positional Embeddings (Positional Encoding)
- Relative Positional Embeddings (Relative PE)
- Rotary Positional Embeddings (RoPE)
- Attention with Linear Biases (ALiBi)
- Transformer without Positional Embeddings (NoPE)

それぞれ解説していきます。

## Absolute Positional Embeddings (APE) あるいは Positional Encoding

[Attention is all you need](https://arxiv.org/abs/1706.03762) の最初の Transformer に採用されている Positional Embeddings。
最初は Positional Encoding という名前でした。

APE では、sin と cos 関数を使用し、位置 $pos$ と次元 $i$、モデルの埋め込み次元 $d_{model}$ に対して、次のように計算されます。
- $PE(pos, 2i) = \sin(pos / 10000^{2i/d_{model}})$
- $PE(pos, 2i+1) = \cos(pos / 10000^{2i/d_{model}})$

APE は実装が容易ですが、シーケンスの長さが変動する場合（例：学習した文より長い文を扱う場合）に性能が悪くなるという欠点がありました。

## Relative Positional Embeddings (Relative PE)

APE は、シーケンスの長さが変わる場合に性能が悪くなるという欠点があったので、相対的な位置を見る Relative PE が提案されました。

Relative PE では、相対的な位置情報を self-attention 機構に組み込んでいます。

- **変更前**
    - $ e_{ij} = \frac{(x_iW^Q)(x_jW^K)^T}{\sqrt{d_z}} $
- **変更後**
    - $ e_{ij} = \frac{(x_iW^Q)((x_jW^K + a^K_{ij})^T)}{\sqrt{d_z}} $
        - ここで $a^K_{ij}$ は入力要素 $x_i$ と $x_j$ 間の相対位置を表すベクトル

これによって、シーケンスの長さが変わっても対応できるようになった一方、計算コストが高くなるという欠点が出てきました。

## Rotary Positional Embeddings (RoPE)

RoPE は、Relative PE と同じように、APE の「シーケンスの長さが変わる場合、性能が悪くなる」という欠点に対応するため提案されました。

RoPE では以下のような回転行列を使います。
```math
R_i = \begin{bmatrix} \cos(\theta_i) & -\sin(\theta_i) \\ \sin(\theta_i) & \cos(\theta_i) \end{bmatrix}
```
$θ_i$は位置$i$に応じた回転の角度です。回転を利用することで、トークン間の相対距離が増加するにあたって内積が減衰するので相対位置を表現しています。

RoPE は [LLaMA](https://arxiv.org/abs/2307.09288) 系のモデルなど広く利用されており、現在の主流な位置エンベディングです。

## Attention with Linear Biases (ALiBi)

シーケンスの長さの変化に対応すべく Relative PE や RoPE が提案されたものの、Relative PE は効果あるけどメモリも食う上に遅く、RoPE は Relative PE ほど効果がありませんでした。
それならもっと早くて性能も良いものを作ろうとしてできたのが ALiBi です。

ALiBiでは、位置情報として、クエリキーペア間の距離に基づいた静的なバイアス $M$ を加算します。
```math
 \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T + M}{\sqrt{d_k}}\right)V 
```
ここで、$Q, K, V$ はそれぞれクエリ、キー、バリューの行列、$d_k$ はキーベクトルの次元です。
静的なバイアス $M$ は行列で表され、その要素 $M_{ij}$ は $-m \times |i-j|$（ここで $m$ はハイパーパラメータ）によって計算されます。この式では遠くのペアよりも近いペアのスコアが相対的に高くなります。

ALiBi は [BLOOM](https://arxiv.org/pdf/2211.05100.pdf) に利用されています。

## Transformer without Positional Embeddings (NoPE)

位置情報を入れてもそれほど効果が見られないなら、いっそのこと抜いてしまおうというのが NoPE です。

もちろん、位置情報を抜くことで、シーケンス内のトークン間の位置関係をモデルが把握できず、これにより、位置情報が重要タスクにおいては、パフォーマンスの低下が起きる可能性があります。

ただし、位置に依存する Absolute Positional Embeddings と比較すると、固定された位置パターンに依存しなくなるため、任意のシーケンス長に対応できますし、そもそも計算工程を一つ省くため計算量が少なくなります。

NoPE は比較的新しい手法のため、NoPE を使った有名モデルはまだ見たことがありませんが、メリット・デメリットを理解して使う分には有効な手法になる可能性があります。
Angular勉強日記①　アプリケーション作成

# はじめに
Angularの勉強を始めたので記録としてまとめていきます。
初歩的な部分が多いかと思いますが悪しからず…

# 今日やること
* Angularのプロジェクトを新規作成する
* ローカルで実行確認してみる

# バージョン情報
事前に必要なツールをインストールしています。
参考：https://angular.jp/guide/setup-local
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130442/fa82cf52-6085-0fd0-c41e-82f25899fc4b.png)

# アプリケーションの作成、起動
こちらのページを参考に作っていきます。
https://angular.jp/tutorial/tour-of-heroes/toh-pt0

### ワークスペースの作成
Angularはワークスペースという箱を作って、その中にプロジェクトを作るという構造のようです。
https://angular.jp/guide/file-structure

任意の作業フォルダの中で右クリックし、「ターミナルで開く」をクリックするとPowerShellが立ち上がるので、コマンドを実行します。
ここではワークスペースの名前を「angular-0420」としました。 
```
ng new angular-0420
```
### 使用するスタイルシートフォーマットの選択
スタイルシートのフォーマットの選択が求められました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130442/65d208c2-1e37-862b-f65e-309dfbecbf91.png)

どれが良いのか迷ったので違いを調べてみたところ、このような特徴があるようです。
 * css…一番シンプルでわかりやすい。機能が限定的。
 * sass…インデントベースの構文が特徴で、cssよりも様々な機能を利用できる。
 * scss…sassと同じ機能を持っている。記述方法はcssと同様のセミコロンと波括弧を使用する。
 * less…JavaScriptベースでサーバーサイドでも動作が可能。

 参考：https://susanweblog.com/css-scss/
 
プロジェクトの規模に合わせたり慣れている記述方法を選ぶのが良さそうです。
 今回はSass(SCSS)にしました。

### SSR, SSG使用有無の選択
次は「サーバーサイド レンダリング (SSR) と静的サイト生成 (SSG/プリレンダリング) を有効にしますか?」という質問が来ました。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130442/e05b1c47-753e-6723-cc94-5f1783be7420.png)

ここでNoを選択するとSPAが生成され、SSRやSSGの機能を使用したい場合はYesを選ぶと良いようです。
https://angularstart.com/modules/angular-getting-started/1/
https://zenn.dev/rinda_1994/articles/e6d8e3150b312d

今回は簡単に動作確認したいだけなのでNoを選びます。

### 完成
しばらく待つと無事作成完了しました！
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130442/8206cb65-8001-8c35-e6e0-36749893784f.png)

作業フォルダの中を見てみると、プロジェクト用のファイルが生成されているのが確認できます。


### アプリケーションをサーブする
早速アプリケーションを起動してみます。
```
cd angular-0420
ng serve --open
```
自動でブラウザが立ち上がり、アプリケーション画面が確認できました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130442/09029809-c235-3d7f-2f2e-525eccb03f7e.png)

ctrl + cで停止します。

# まとめ
本当にすぐ簡単にアプリケーションの作成ができました。
これから中身を詳しく見ていきたいと思います。
【Unity】IL2CPPビルド時にCould not set up a toolchain for Architecture *** が発生する

# 現象
Windowsビルド時にIL2CPPでビルドしようとすると以下のエラーが発生しました。
```
Internal build system error. BuildProgram exited with code 1.
error: Could not set up a toolchain for Architecture x64. Make sure you have the right build tools installed for il2cpp builds. Details:
IL2CPP C++ code builder is unable to build C++ code. In order to build C++ code for Windows Desktop, you must have one of these installed:
```

# 解消方法
VisualStudioがインストールされていないのが原因の様です。
UnityHubから利用しているUnityバージョン`AddPlatform`から`Microsoft Visual Studio Community 【バージョン】`をインストールするとエラーが解消されます。
Dify インストール（Docker篇）


1. GitHubからプロジェクトをクローンします。

```
git clone https://github.com/langgenius/dify.git
```

2. クローンしたプロジェクトのディレクトリに移動します。

```
cd dify
```

3. 次に、プロジェクト内のdockerディレクトリに移動します。

```
cd docker
```

4. そして、Spotlight検索を使用してDocker Desktopを起動します。

5. Docker Desktopが起動したら、ターミナルまたはコマンドプロンプトを開き、プロジェクトのルートディレクトリ（dify）に移動します。

6. Docker Composeを使用して、プロジェクトのDockerコンテナーを起動します。これにより、プロジェクト内のすべてのサービスが起動します。

```
sudo docker-compose up -d
```

7. ブラウザで http://localhost/install にアクセスし、初期化インストールプロセスを開始します。

8. Difyが開くと、メールアドレス、名前、パスワードを登録する必要があります。この手順はOpen-webuiと同じです。

9. 言語の選択が可能ですが、日本語を選択すると、一部の文字が翻訳されていない可能性があるため、英語をお勧めします。

10. 最後に、Difyの時刻設定を日本標準時に変更することを検討してください。
AWS 認定資格Solutions Architect - Associate について

- SAA を受けてきたのでそのまとめです

# なぜ資格を取ろうとしたか？
- 元々認定資格への興味がなかったが、周りに認定資格を持っているエンジニアも多く、同じ視点で会話したいと考え始めたのがきっかけです

# これまでの戦績
| 資格名 | 受験日 | 合否 | スコア |
| -- | -- | -- | -- |
| CLF-C02 | 2024/1/27 | 合格 | 769 |
| SAA-C03 | 2024/4/5 | 不合格 | 706 |
| SAA-C03 | 2024/4/19 | 合格 | 735 |

# SAA を受けてみて
- 2024 年4 月 〜 受験料が値上がるので、勢いで3/31 に受験申し込み
    - 保険のため、再受験無料のパウチャーを使う
- 数時間程度(5 時間以下) の勉強で4/5 に受験するも撃沈
    - ギリギリ落ちる
- 2 週間のインターバルを置き再受験
    - 2 週間の間は、Udemy で問題を解き、正解/不正解関係なく解説に目をと押す
    - この繰り返しです
- 4/19 に再受験するもギリギリで合格
    - 試験中も勉強不足は否めない状態...

# 次に向けて
- DVA-C02 をまた近いうちに受験予定

# まとめ
- 勢いで良いと考えるので、まずは試験の予約を入れる
    - ここがスタートラインで、これをやらないとズルズル行きます
        - CLF の勉強を始めたのは2023 年9 月からですが、いつ受験するかを決められずズルズルと時間だけが過ぎて行きました
- あとは普段からaws を触り、問題をもくもくと解いていくだけ

# おまけ
- 自分はJR の駅にあるSTATION WORK を使い毎回受験していますが、意外と駅はうるさいし、個室のスペースの物珍しさから受験中に外から扉を開けてくる人もいたりです...
- 今後難易度も上がってきて集中力が必要になると思うので、一度テストセンターでの受験も考えてみようです
シンプルにGithubへpushする最短経路

# Githubにとりあえずpushしてコード管理したい

## 対象者

- とにかくgithubを使ってみたい
- 最低限のgitコマンドを知りたい

## 前提

- Githubアカウントを作成済み
- Githubでリモートリポジトリを作成済み

## :notepad_spiral: 最短経路図

```mermaid
sequenceDiagram
    participant U as ユーザー
    participant LR as ローカルリポジトリ
    participant RR as リモートリポジトリ

    U->>RR: git clone (リポジトリクローン)
    RR-->>LR: リポジトリデータ
    U->>LR: ファイル編集
    U->>LR: git add (変更をステージ)
    U->>LR: git commit (変更をコミット)
    U->>RR: git push (変更をプッシュ)
    LR-->>RR: 更新データ
```

### シーケンス図の説明

- **リモートリポジトリからクローン**:
  - ユーザーがリモートリポジトリからローカルリポジトリに対して `git clone` コマンドを実行し、リポジトリのデータがローカルに複製されます

```bash:git clone
git clone <リポジトリURL>
```

- **ファイルの編集とステージング**:
  - ユーザーがファイルを編集し、`git add` コマンドでこれらの変更をステージングエリアに追加します

```bash:git add
git add .
```

`「.」(ドット)`を忘れずに。変更をすべてステージングできます。

- **コミットとプッシュ**:
  - ステージングされた変更を `git commit` コマンドでコミットし、その後 `git push` コマンドを使用してリモートリポジトリにプッシュします

```bash:git commit
git commit -m <コメント>
```

```bash:git push
git push -u <remote repository名> <branch名>
```

ローカルの master ブランチの変更をリモートリポジトリ (origin) の master ブランチにプッシュします。

:::note info
`-u` オプションは、以後 `git push` や `git pull` コマンドを使用する際にリモート名とブランチ名を省略可能にするため、アップストリーム (追跡) リンクを設定します。
:::
Google Mock の EXPECT_CALL 定義順について

# ０．はじめに

[Google Mock ドキュメント日本語訳（複数の Expectation を利用する）](http://opencv.jp/googlemockdocs/fordummies.html#fordummies-using-multiple-expectations)

>Google Mock のデフォルトでは，モックメソッドが呼び出されると，引数にマッチするアクティブな Expectation が見つかるまで，定義順とは逆方向に Expectation を探索します

# １．簡単なテストコードで動作を確認

``` cpp:テスト対象とモック
// モック
class MockMyCalck
{
public:
	MOCK_METHOD2(add, int(int, int));
	MOCK_METHOD2(sub, int(int, int));
} *mockPtr = NULL;

int add(int a, int b)
{
	EXPECT_NE(mockPtr, (MockMyCalck*)NULL);
	return mockPtr->add(a, b);
}

int sub(int a, int b)
{
	EXPECT_NE(mockPtr, (MockMyCalck*)NULL);
	return mockPtr->sub(a, b);
}

// テスト対象関数
void function(void)
{
	add(1, 2);
	add(3, 4);
	add(5, 6);
}
```


``` cpp:テスト対象関数と同じ順番に定義
TEST(Sample, 00)
{
	MockMyCalck mock;
	mockPtr = &mock;

	// Define Expection
	EXPECT_CALL(*mockPtr, add(1, 2)).Times(1);
	EXPECT_CALL(*mockPtr, add(3, 4)).Times(1);
	EXPECT_CALL(*mockPtr, add(5, 6)).Times(1);
	
	function();
}
```


``` cpp:適当な順番に定義
	// Define Expection
	EXPECT_CALL(*mockPtr, add(5, 6)).Times(1);
	EXPECT_CALL(*mockPtr, add(3, 4)).Times(1);
	EXPECT_CALL(*mockPtr, add(1, 2)).Times(1);
```

``` cpp:ループで定義
	// Define Expection
	std::vector<std::vector<int>> v = {{1, 2}, {3, 4}, {5, 6}};
	for(auto x : v){
		EXPECT_CALL(*mock_ptr, add(x.at(0), x.at(1))).Times(1);
	}
```

``` cpp:実行結果
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from Sample
[ RUN      ] Sample.00
[       OK ] Sample.00 (0 ms)
[ RUN      ] Sample.01
[       OK ] Sample.01 (0 ms)
[ RUN      ] Sample.02
[       OK ] Sample.02 (0 ms)
[----------] 3 tests from Sample (0 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 3 tests.
```
Scalaの制御構文

## 文と式の違い
文と式の違いは評価すると値になるか、ならないかが異なる

文はその部分を評価しても値にならない

```scala
val value = 2
```

式はその部分を評価すると値になる

```scala
value1 == value2
```

## if式

式なので値を返す
三項演算子として利用することがある

```scala
val number = 2
val result = if (number % 2 == 0) "even" else "odd"
println(result)
// output
even
```

`else`を抜くと値を返さないようになる

```scala
val number = 2
val result = if (number % 2 == 0) "even"
println(result)
// output
()
```

## match式

他のプログラミング言語の`switch`を`scala`では`match`を使用する
式なので値を返す

```scala
val station = "kasumigaseki"

val subway = station match {
  case "kasumigaseki" => "hibiya, chiyoda, marunouchi lines"
  case "uchisaiwaicho" => "mita line"
  case _ => "no match"
}

println(subway) 
// output
hibiya, chiyoda, marunouchi lines
```

型の判定もできる

```scala
val anyValue = 1234

val result = anyValue match {
  case s: String => "String"
  case n: Int => "Int"
  case d: Double => "Double"
  case _ => "No Match"
}

println(result)
// output
Int
```

case中にif式を挟むこともできる

```scala
val address = "taitoward-minowa-xxxx"

val result = address match {
  case value if address.startsWith("taitoward") => "台東区"
  case value if address.startsWith("minatoward") => "港区"
  case _ => "No Match"
} 

println(result)
// output
台東区
```

## for式

基本的な書き方


```scala
for (i <- 1 to 3) println(i)
// output
1
2
3
```

untilにすると最後を含めないようにできる

```scala
for (i <- 1 until 3) println(i)
// output
1
2
```

増加率は`by`で変更することができる

```scala
for (i <- 1 to 10 by 2) println(i)
// output
1
3
5
7
9
```

配列、Mapの繰り返し

```scala
val array1 = Array(1, 2, 3, 4)
for (i <- array1) println(i)
// output
1
2
3
4
```

```scala
val map1 = Map(1 => "banana", 2 => "orange", 3 => "apple")
for ((k, v) <- map1) println(s"$k, $v")
// output
1, banana
2, orange
3, apple
```

繰り返し中での条件分岐

```scala
val addresses = Array("tokyo, minato, nishishinbashi", "tokyo, taito, minowa", "tokyo, shibuya, dougenzaka")

for(address <- addresses if (address.startsWith("tokyo, minato")) println(address)

// output
tokyo, minato, nishishinbashi
```

二重for文

```scala
for (x <- 1 to 3;y <- 1 to 3) println(s"$x, $y")
// output
1, 1
1, 2
1, 3
2, 1
2, 2
2, 3
3, 1
3, 2
3, 3
```

## while式

```scala
var num = 0
while(num <= 3){
  println(num)
  num += 1
}
// output
0
1
2
3
```

`break`や`continue`は構文として用意されていない
初代Raspberry Pi Type Bのカメラを起動してみた

## はじめに
ずいぶん昔に購入したRaspberry Pi Type Bを久々に起動してみて、いろいろと試してみたいと思っています。
今回はカメラを起動して動かしてみました。


## カメラを起動する前に
まず、LXTerminalを起動し、以下のコマンドを入力してraspi-configを起動します。
（カメラはデフォルトでは **OFF** の状態ですので、使用可能なようにraspi-configで **ON** 状態に設定します）

`pi@raspberrypi ~ $ sudo raspi-config`

ちなみにsudoコマンドを付け忘れると以下のようなエラーが出力されますので、ご注意を！

`pi@raspberrypi ~ $ Script must be run as root. Try 'sudo raspi-config'`

![berry006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/f426a6b0-1557-4672-07d2-fc9f00c1d711.jpeg)

メニューから **5 Enable Camera** を選択します。そうすると次の画面が表示され、カメラを有効にするかを聞かれます。ここで **Enable** を選択します。

![berry011.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/a1aecdc9-be23-a901-f7c1-35512b675c11.jpeg)
**Enable** を押下すると次の画面が表示され、再起動を要求されます。もちろん **はい** を選択して再起動します。
![berry012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/7f8be17b-040a-fb05-3fcb-88c4dd09b654.jpeg)

## カメラ起動
再起動後はカメラが使えるようになっています。Raspberry Piではカメラ用のコマンドとしてraspistillやraspividが用意されているようです。
  raspistill: 静止画撮影
  raspivid: 動画撮影
  

今回はwidth=320 height=240で静止画を撮影してみました。幅や高さを指定せずにデフォルトで撮ると2592x1944のJPEGイメージが撮影できます。サイズは数Mbytesになるので気をつけてください。

`pi@raspberrypi ~ $ raspistill -w 320 -h 240 -o test.jpg`

今回の被写体は、うちにいるプーさんです。
![test_bear.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/7fda0b6f-2c0e-394f-7bac-bd3564ea02d3.jpeg)

動画を撮影する場合は以下のコマンドを使います。

`pi@raspberrypi ~ $ raspivid -w 320 -h 240 -o test.h264`

ちなみに静止画にはEXIFも含まれるようです。また動画はh.264の生データでコンテナには含まれていないようです。Windowsであれば、VLC Media Playerなどを使えば再生できます。

## 困ったこと
さてRaspberry Piで撮影したデータをどうやってWindowsに移動させるか。このRaspberry PiはUSBポートが2つしかなくキーボードとマウスを接続すると全部埋まってしまいます。ということでUSBハブをRaspberry Piに接続してUSBポートを増やすしかなさそうだなという結論になりました。
無事、Windowsにデータを移動させることができました！
論文紹介　FAPM

## はじめに

画像に関する異常検知の論文を簡単に紹介します。解釈間違ってたらすいません。[PatchCore](https://arxiv.org/abs/2106.08265)ベースの手法ですので、PatchCoreを知らない人は先にそっちを読んだほうがいいかもです。

論文タイトル
[FAPM: Fast Adaptive Patch Memory for Real-time Industrial Anomaly Detection](https://arxiv.org/abs/2211.07381)

作者　Donghyeong Kim,  Chaewon Park, Suhwan Cho, Sangyoun Lee, Yonsei University, Seoul, Korea Korea Institute of Science and Technology (KIST) 　延世大学、韓国の有名大学

## 軽くPatchCoreの説明
学習時
①学習済みCNNモデルの中間層から特徴ベクトルを抽出
②コアセットサンプリングして冗長な特徴ベクトルを削除
③メモリバンクに保存

テスト時、メモリバンク内の特徴ベクトルとテストデータの特徴ベクトルの距離で異常かどうかを判定

<img width="700"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772632/762057c6-b2f5-59e7-1c31-ef0376c6226a.png">

## 提案手法
<img width="700"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772632/b47488e9-e73c-eada-5189-40b1272b38fc.png">

- PatchCoreをより高速に推論できるように改良したFast Adaptive Patch Memory（FAPM）を提案する

- パッチおよびレイヤーレベルでメモリバンクをつくり、不必要な繰り返し計算を削減する
- パッチレベルの特徴ベクトルの分布に応じて、コアセットサンプリングの割合を変える

- より高速で正確な検出のためのパッチ単位の適応的コアセットサンプリングを行う

## パッチ単位のメモリバンク
- 産業の異常データセットは主に、整列した画像で構成されており、各クラスの同じ場所に類似した情報が存在する

- この仮定に基づいて、FAPMは学習時にすべての画像の特徴ベクトルを単一のメモリバンクに保存するのではなく、各パッチの埋め込み特徴ベクトルを別々に保存する

- PatchCore同様に事前学習済CNNモデルを使用して、正常画像の特徴ベクトルを抽出する
- モデルの図だと4分割しているところを論文だと49分割にしてパッチごとに特徴ベクトルをメモリバンクに保存していく

## レイヤー単位のメモリバンク
- PatchCoreでは通常、CNNの中間層の特徴ベクトルを連結して、メモリバンクに保存している

- 中間層の出力Layer2とLayer3の連結は、より深い層の特徴ベクトルを不必要にアップサンプリングし、メモリバンクのベクトルサイズを増加させ、計算コストが高くなる
- それに加えて連結することで次元数も増加する

→レイヤーごとにメモリバンクの構築

## パッチごとの特徴ベクトル分布と適応的コアセットサンプリング
<img width="400"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772632/380bd02e-74fa-cf87-7550-fd5478589542.png">

- パッチごとにメモリバンクの特徴ベクトル分布が異なる

- パッチごとの特徴ベクトルをK個のクラスターにわけて、各クラスターのサイズを計算する

- 各クラスターのサイズの最大値が閾値よりも大きいパッチに対してのみ、再度コアセットサンプリングを行い、分布が大きいパッチはより多くの特徴ベクトルを残すようにする(サンプリングレートを増やす??)

<img width="400"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772632/8dc756ff-e20c-560b-7759-7fcf9642de27.png">

## PatchCoreと提案手法の比較
- 正常な画像全体の結合された中間レベルの特徴ベクトルをN_v個を保存し、単一のメモリに保存する

- テスト画像の中間レベルの特徴ベクトル数N_𝑡とメモリ内のサンプリングされたベクトルとのすべての距離を計算する

- PatchCore 計算コスト：N_v×N_t

FAPM
- パッチの数N_Pごとに計算を繰り返すが、ベクトルの数はテスト画像とメモリベクトルの両方でパッチの数によって減少し、計算コストを1/N_pにする

- FAPM 計算コスト： N_p×N_V/N_p×N_t/N_p 

## 結果
![スクリーンショット 2023-12-18 192836.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772632/cbe3dbf8-683f-bf64-c6f0-0c2d5d9e3783.png)

<img width="400"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772632/e5bcd9b8-e641-37f7-4d94-389bcdcca4ce.png">

<img width="400"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772632/cbd1b96c-ff10-a8cc-2f34-45ede0d251b5.png">

## 終わりに
シンプルで実用性高そう。ただScrewみたいな位置ずれが起きるデータにはパッチ単位で分けてメモリバンク作るより、最初からサンプリングレート下げたほうがリッチなメモリバンク作れそう。
503を返すモック用Webサーバーの立ち上げ

「503エラーのテストしたいのですが、何か方法思いつきませんか」と質問されたので。
（おそらく何かしらのAPIを提供しているサーバーがエラーを返したときを想定しているのかな、と推測）。

API叩くツール等でモックサーバーを提供していると思われるのでそれを利用する、
AWSのアカウント等があるならロードバランサーを立ち上げる、
などいろいろな解決方法はあるかと思いますが、取り急ぎかつローカルでの検証であればpythonで十分かなーと単に503を返す標準ライブラリで起動できるサーバーをお勧めしました。
nodejsやRuby等でも同じことはできますが、仕事用の端末に入ってないのでPythonで。

```python
from http.server import HTTPServer, BaseHTTPRequestHandler

class My503Handler(BaseHTTPRequestHandler): # BaseHTTPReuqestHanderに基本的な部品がある
    def do_GET(self): # do_GETでGETメソッドがハンドリングできる
        self.protocol_version = 'HTTP/1.1'
        self.send_response(500, '')
        self.send_header('Content-Type', 'text/html')
        self.send_header('Content-Length', '0') # 説明を読む限り'HTTP/1.1`であれば必須のよう
        self.end_headers()

HTTPServer(('localhost', 8000), My503Handler).serve_forever() # HTTPServerの起動
```

ただ、これ止めてもポートを掴んじゃっている気がします。`serve_forever` が問題なのか。。。
Android アプリで Firebase ネットワークタイムアウトエラー：A network error (such as timeout, interrupted connection or unreachable host) has occurred. 

# これなに
Flutter でアプリ実装したけど、Android でネットワークタイムアウトエラーになってしまう事象に遭遇したので調べた
```zsh
E/RecaptchaCallWrapper(25265): Initial task failed for action RecaptchaAction(action=signUpPassword)with exception - A network error (such as timeout, interrupted connection or unreachable host) has occurred.
```

# エラー内容全文
なんかよくわからないけどネットワークがタイムアウトしたらしい。
```zsh
I/FirebaseAuth(25265): Creating user with hoge@hoge.com with empty reCAPTCHA token
W/System  (25265): Ignoring header X-Firebase-Locale because its value was null.
D/EGL_emulation(25265): app_time_stats: avg=25.98ms min=9.95ms max=389.89ms count=39
E/RecaptchaCallWrapper(25265): Initial task failed for action RecaptchaAction(action=signUpPassword)with exception - A network error (such as timeout, interrupted connection or unreachable host) has occurred.
I/flutter (25265): *** registerUserInFirebase > Result: [firebase_auth/network-request-failed] A network error (such as timeout, interrupted connection or unreachable host) has occurred.
```

# 解決方法
`android/app/src/main/AndroidManifest.xml` で以下のようにインターネット接続を許可する。
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- ↓ Allow to exchange via the internet -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- ↑ Allow to exchange via the internet -->
```

# 別の理由もある
Android エミュレーターとかデバイスのネットワーク接続状態も確認しましょう。
実はそっちが繋がってなかったら通信できなくて当たり前なので。