OmniAICreator/Qiita-1.07M huggingface dataset:
cscの作法 その355

# 概要
cscの作法、調べてみた。
丸いボタンを見つけたので、やってみた。

# 参考にしたページ。

https://qiita.com/ueruku/items/3693da7ea6a41664bca6

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/dcab37c9-dfef-cbef-6317-6169acb5a6bf.png)


# サンプルコード

```
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace App
{

	public partial class Form1: Form {
		EllipseButoon button1;
		public Form1() {
			Text = "maru";
			ClientSize = new Size(300, 200);
			button1 = new EllipseButoon();
			button1.Location = new Point(20, 20);
			button1.Text = "make";
			button1.Click += new EventHandler(button1_Click);
			Controls.AddRange(new Control[] {
				button1
			});
		}
		private void button1_Click(object sender, EventArgs e) {

		}
		[STAThread]
		public static void Main() {
			Application.Run(new Form1());
		}
	}
}




```

以上。
FlutterでCognitoのIdTokenやAccessTokenをログ出力すると署名が壊れる？

ググるとズレた話題の議論をぐるぐる巡ることになり、数時間ハマったので。
ChatGPTさんも知らなかったです。

# 問題
Amazon Cognito から取得したトークンを Flutter アプリ内から debugPrintで ログに出力し、コピペして認証に使おうとすると、認証に失敗します。jwt.io でトークンを検証してみると署名が壊れています。なんで？

# 原因
dart の debugPrint はどんなに長い文字列でも省略せずに出力してくれるのですが、Flutterのログ（flutter logs）でコンソールに表示される文字列は1,024文字が上限です。

Cognitoのトークンは1,024文字をちょっと超えているので、ログ上は一見正常に見えるトークンでも末尾が切れており、署名が壊れたトークンとなってしまいます。

# 解決法
1024文字を超える文字列はFlutter DevTools の logging ビューを使うと正常に表示できるのでこちらを使います。別解としては、Flutterアプリ内にデバッグ機能としてトークン文字列を表示したり、クリップボードにコピーする機能を付けるなどがあると思います。

# おわりに
意外と気が付きにくいよ！
Laravel 6から Laravel 9にアップデートする際にやったこと

個人開発でちょっとしたLaravelのWebアプリを作ったことがあって、それをリニューアルしたいと思ってバージョンをあげました。Laravel 6は既にサポートが終了していたので、選択肢としては9と10があったのですが、アップデート手順の紹介がされているサイトの多くが6から9へのアップデートに合わせました。
※おそらく同じような手順で10へのアップデートもできると思います。

## まずはPHPバージョンのアップデート
自分のPCはWindowsで手早く修正したかったので、PHPはXAMPで用意しました。
前に入っていたXAMPが古かったので、最新版をダウンロードしてインストールを実施しました。
XAMPはApacheも含んでいるため、htdoc配下にプロジェクトファイルを置いて動作確認しました。

## Composerのアップデート
Laravelをアップデートする前にまずはパッケージマネージャを新しくする必要があるので、
Composerをアンイストールし、最新版のComposerをインストールしました。

## composer.jsonの書き換え
Laravelのバージョン変更によって、依存するライブラリ群のバージョンも合わせる必要があるので、
自分の場合は、下記のようにcomposer.jsonを書き換えました。
※ここは人によって入っているライブラリが異なるのでここにないものが入っている方は各自で調べてください。

変更前
```json
    "require": {
        "php": "^7.2",
        "barryvdh/laravel-debugbar": "^3.6",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "^6.0",
        "laravel/tinker": "^1.0"
    },
    "require-dev": {
        "facade/ignition": "^1.4",
        "fzaninotto/faker": "^1.4",
        "laravel/ui": "1.0",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^3.0",
        "phpunit/phpunit": "^8.0"
    },
```

変更後
```json
    "require": {
        "php": "^8.2",
        "barryvdh/laravel-debugbar": "^3.6",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "^9.0",
        "laravel/tinker": "^2.7",
        "laravel/ui": "^4.0"
    },
    "require-dev": {
        "spatie/laravel-ignition": "^1.0",
        "fakerphp/faker": "^1.9.1",
        "mockery/mockery": "^1.4.4",
        "nunomaduro/collision": "^6.1",
        "phpunit/phpunit": "^9.5.10"
    },
```

## ソースの修正
使っていたライブラリや書き方が変わってしまったところがあるので、エラーが出ているソースを順次直していきました。

自分の例をあげておきます。

### Exceptions\Handler.php
・use Exception;　を　use Throwable;　に変えて、Exceptionと記述のあるところをThrowableに変更
・use Illuminate\Validation\ValidationException;　のuse文を追加

### Controller.php
・use Throwables;が必要なところを追加

### Middleware\TrustProxies.php
・headersの変数定義を次のように変更

変更前
```
    protected $headers = Request::HEADER_X_FORWARDED_ALL;
```

変更後
```
    protected $headers =
        Request::HEADER_X_FORWARDED_FOR |
        Request::HEADER_X_FORWARDED_HOST |
        Request::HEADER_X_FORWARDED_PORT |
        Request::HEADER_X_FORWARDED_PROTO |
        Request::HEADER_X_FORWARDED_AWS_ELB;
```

## まとめ
Laravelのアップデートは使ってるライブラリによって、修正手順が大きく異なるので、一概にこの方法で上手くいくとは言えません。ただやり方の流れ自体は変わらないと思います。

1. PHPやComposerのアップデート
1. composer.jsonの依存関係を考慮したライブラリのアップデート
1. 各ソースでエラーが出ている箇所をエラー名で検索して解決策を探す

モノによっては解決策が海外のサイトにしか載ってないってことがザラにあるので、
英語だからといって敬遠せずにちゃんと内容を見て該当するか確認しましょう。

※最近のブラウザの翻訳機能は精度が良いので翻訳すればだいたいわかると思います。
　あとはChatGPTで聞いてみるというのも一つの方法かもしれません。
Azure Synapse Analyticsでデータパイプライン構築を行う（Microsoft Learning活用）

# 1.取り組んだきっかけ
## Azureのデータパイプライン構築についてのサービスを知りたかった

GCPやsnowflakeなどのサービスについては少し触った経験があったが、Azureについては触れたことがなかった。
(AWSもAthenaのクローラーなども触ったことがあった)

GCP・Azure・AWSこの３大クラウドサービスを是非とも触ってみたかった。

調べていくと、何やらAzure Synapse Analyticsというものがあるらしい

要約すると、
S3やData Lake Storage Gen2などのデータレイクサービス
Apache Sparkなどを動かすことができるDataBricks（ETLや機械学習モデル構築）
Synapse SQL（DWH）
これらのサービスの統合をサポートするサービスだそう。

私自身Apache Airflowなどを学習していた部分があったが、
学習コストがかなり高いなと感じていた。

GUI上で操作できたらすごい便利だな〜と感じていたので、とてもハマった

# 2.参考にした学習サイト

https://learn.microsoft.com/ja-jp/training/modules/build-data-pipeline-azure-synapse-analytics/

こちらが参考にさせていただいた学習サイトになります。

あくまでもこのサイトは、Synapse AnalyticsのGUI上でデータパイプライン構築しようという題材から、
事前にsetupのコードが渡されている。

すぐにGUI上でパイプライン構築したいな〜と思われている方にはとても良いが、

Data Lake Storage Gen2や
Synapse SQL（DWH）のセットアップからやってみたいという方には少し物足りないものかと思います。

作成したパイプラインは以下の通りになります

![スクリーンショット 2023-06-10 12.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/dd3fd25b-88cb-4373-8ced-c9f5e20d09dd.png)

①データレイクサービスからテキストデータを
DWHからテーブルを参照して、外部結合し
②マッチしたデータを更新して
③マッチしないデータはそのままにし
④不要な列を削除して
⑤元のDWHを更新するというような作業になってます」

これが全て簡単に実行できました。

是非活用してみてください

# 3.これからの展望
以下のUdemyの教材がありました。
評価もかなり高く、時間もかなり長いので、勉強になりそうです。

https://www.udemy.com/course/azure-synapse-analytics-for-data-engineers/

日本語が対応していないのがとても弱みですが、サービス概要などが図で表されているので、
なんとか解読できるようにしていきます。
ブラウザ版VSCode周りの自分メモ

# VScodeの種類
- 通常のローカルのインストールするVSCode
- VSCode.dev　MS公式サイトをブラウザで開き使うブラウザ版
- VSCodeServer　自分の環境で動かすブラウザ版


## 通常のローカルのインストールするVSCode
多くの方が使っているだろうローカルインストールのVSCode
https://azure.microsoft.com/ja-jp/products/visual-studio-code


## VSCode.dev　MS公式サイトをブラウザで開き使うブラウザ版
拡張機能がかなり限定されますが、URL開いたらいきなり使えるって意味で便利。
https://vscode.dev


## VSCodeServer　自分の環境で動かすブラウザ版
現在私が使っている、自分の環境でVSCodeServer動かせして、ブラウザ開発できるVScode。
Dockerで開発用ライブラリ含めまとめて構築して使っています。

**非推奨になってます!!**
https://code.visualstudio.com/blogs/2022/07/07/vscode-server

>We've released changes to how you can connect to the VS Code Server since this blog was >published. Check out the December 2022 blog post for the latest guidance.

>>このブログの公開以来、VS Code サーバーへの接続方法の変更をリリースしました。最新のガイダンスについては、2022 年 >>12 月のブログ投稿をご覧ください。

久しぶりに新規インストールしようとしたらエラーが出て気づきました。

以下だとインストールファイルではなくHTMLがダウンロードされ、実行時にエラーになります。
`wget -O- https://aka.ms/install-vscode-server/setup.sh | sh`

色々調べると今でもLinux版ならインストールできましたが、かなりお手軽からは離れてしまいました。。。。。
この方法もいつまで使えるか不明ですし。。。。
ウーム、インストール方法を公開しとけば、誰かが簡易化してくれるかな。

### Local版VSCodeServerのインストール方法
> こちらに書いてみました。
> https://qiita.com/zen7sky/items/cad8b91136c8b56da80a

## VSCodeServerの不満
多くの拡張が使えるようになっていますが、 「Dev Containers」がまだ使えないです。インストールしようとすると

```
'Dev Containers' 拡張機能は Web 版の Visual Studio Code では使用できません。
詳細については、[詳細情報] をクリックしてください。
```

これ使えると、開発IDE部部分と開発部ライブラリ部分分離できるんだが。。。。。。



# おまけ過去使っていたWeb版IDE達
## OpenVscode-server
VScodeとほぼ同じです。ただし拡張インストール元がＭＳ公式と別なので、
MS公式版に乗り換えてしまいました。
こちらもDcokerで動かしてました。

https://github.com/gitpod-io/openvscode-server

## Cloud9
AWSで使えるCloud9を自分の環境で動かせる物です。
それなりにメインで使っていていたのですが、昨今の便利拡張が増える中で物足りなくなりVSCodeに移ってしまいました。
こちらもDcokerで動かしてました。

https://github.com/c9/
節約・貯金Youtubeチャンネルを紹介するWebサイト作成

# 作成物
https://kabuto64425.pythonanywhere.com/

# 使用した技術・サービス
- Python(言語)
- django(フレームワーク)
- sqlite3(データベース)
- pythonanywhere(PaaS)
- YouTubeDataAPI(Youtube情報取得API)
- GoogleColaboratory(コード実験)

# 参考にした記事

https://qiita.com/okoppe8/items/4cc0f87ea933749f5a49#%EF%BC%91%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E4%BD%9C%E3%82%8B

# 概要
管理者があらかじめ登録したYoutubeのチャンネルを掲載するWebサイトです。現在は以下のものを掲載しています。
- チャンネル名
- チャンネルの動画本数
- チャンネル内の最新動画

登録するYoutubeのチャンネルは節約・貯金術を中心に配信しているチャンネルに限定しています。チャンネルの情報は毎日20時に自動更新しています。

# 作成の経緯
python・djangoの勉強のために作成しました。
- シンプルでいいのでとにかく形にする。
- デプロイして公開できるところまで持ってくる

を目標にしており、それはクリアできたのではないかと思います。
節約・貯金をテーマにしたのは自分自身が意識していきたいからです。

# 終わりに
このWebサイトを作成している間に勉強になったことは以前にいくつか記事にしてきました。
でもこれ以外にも勉強になったことはまだあります。
それらについても後日記事にしていきたいです。

https://qiita.com/76r6qo698/items/1e23d257e85590b605d8

https://qiita.com/76r6qo698/items/1d5ef1ba93128e741466

https://qiita.com/76r6qo698/items/b1efc09822aff11c1774

以上です。
【ChatGPT無】嘘吐き報告（ひとつも合っていないわw）


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

　今回は、
　　見事な
　　　ChatGPTさんの
　　　　嘘吐き報告ですw

　あまりに
　　見事だったので
　　　笑ってしまいました。

　どうぞ。
***
「こんばんわ。
漫画家の弓月光が原作のマンガ作品を有名な順にあげてください」
　と問うたところ……

>こんにちは！弓月光さんは、多くの人気な漫画作品を手掛けられています。以下に、いくつかの有名な作品を弓月光さんの原作マンガ作品の中から順番にご紹介します。
>
>1. 『進撃の巨人』（原題: Shingeki no Kyojin） - 弓月光さんの代表作であり、最も有名な作品です。この作品は、人類が巨人と呼ばれる脅威から生き延びるために戦う姿を描いています。
>
>2. 『機動戦士ガンダム 鉄血のオルフェンズ』（原題: Kidō Senshi Gandamu Tekketsu no Orufenzu） - 弓月光さんが原作を担当したガンダムシリーズの作品です。この作品は、戦争の中で生きる孤児たちの物語を描いています。
>
>3. 『ブラックラグーン』（原題: Black Lagoon） - 弓月光さんが原作を手掛けたアクション漫画です。この作品は、違法な商取引を行う海賊船のメンバーたちの活躍を描いています。
>
>4. 『天地創造デザイン部』（原題: Tenchi Sōzō Design-bu） - 弓月光さんが原作を担当した作品で、神が世界を創り上げるためのデザイン部門の活動を描いています。
>
>上記の作品は、弓月光さんが原作を手掛けた中でも特に有名な作品ですが、他にもさまざまな作品があります。弓月光さんの作品は幅広いジャンルにわたるため、興味のある作品を見つけて楽しんでください！

　見てわかるとおり、
　　ひとつも当たっていませんw
　　　作品内容については、
　　　　いいみたい。



「知らないなら、知らないと言ってね」と追加して再送したところ……

>こんばんは。申し訳ありませんが、私の知識は2021年9月までの情報しか持っておりませんので、弓月光という漫画家の最新の作品情報は持っていません。最新の作品情報については、インターネットや漫画の専門サイトをご確認いただくか、最新の情報源を参照してください。ご了承ください。


　ちなみに、
　　以下は、
　　　敬称略で、原作者様方です。
　　こちらは、ウィキペディア調べです。

1. 『進撃の巨人』
　　諫山創（いさやま はじめ）

2. 『機動戦士ガンダム 鉄血のオルフェンズ』
　　矢立肇、富野由悠季

3. 『ブラックラグーン』
　　広江礼威（ひろえ れい）

4. 『天地創造デザイン部』
　　蛇蔵
　　鈴木ツタ（共同原作）
　　たら子（作画）

　それから、
　　弓月光先生は、
　　　『甘い生活　2nd season』
　　　『瞬きのソーニャ』を
　　　　　2023/06/10現在執筆中です。
***
　ChatGPTが、
　　なぜ、あんな嘘を吐いたのか、
　　　考察すると……

　おそらくですが、
　　弓月光先生の原画展のお知らせが
　　　書かれたサイトの同じページに、
　　　　これらの作品紹介が小さくあり、
　　　　　“原作者”というワードが
　　　　　　弓月光先生のみだったから
　　　　　　　ではないか、と。

　しかし、
　　それならば、
　　　弓月光先生のことを知らない
　　　　というのも、
　　　　　またおかしな話で……

　真実は、
　　ChatGPTにも
　　　わからないのでしょうね。
.gitignoreにプロジェクト内のnode_modulesを再帰的に全て追加する

# はじめに
プログラミング学習中の[@kat_log](https://twitter.com/kat__log "Twitter")と申します。

プログラミング学習中、学習中のプロジェクト(リポジトリ)の色んな階層に`node_modules`がある構成で、git管理に戸惑ったのですが、解決したため共有です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1455073/e6bb1b7a-8490-5013-62e2-2b85ce13ffb7.png)

# 結論
.gitignoreの再帰的な指定と、`git rm -r --cached */node_modules`が必要でした。

# 設定

## .gitignoreに以下を追加します
```.gitignore
**node_modules
```

:::note info
.gitignoreファイルはリポジトリ作成時に自動生成されるものではないため、存在しない場合はプロジェクトルート直下に自分で作成する必要があります
:::

## ターミナルにて、下記コマンドを実行します

:::note info
このコマンドが必要なのは、/node_modulesが既にgit管理下に置かれてしまっている場合のみです
:::

```ターミナル
git rm -r --cached */node_modules
```

# （追記）別の端末にてうまくいかない場合
別の端末にてコミットしようとした際
まだ上記の設定が反映されていないと、`fatal: pathspec '*/node_modules' did not match any files`というエラーが出ます
その際は、
1. `git rm -r --cached .`
1. `git add .`
1. `git commit -m "Exclude node_modules directory"`

とするとうまくいきました！

# おわりに
お読みいただきありがとうございました。
自分用のメモ的な知識ですが、どなたかの参考になることがあれば嬉しいです。

# 参考

https://qiita.com/yuikoito/items/1a725ff1507b0134b27a
Nginxのリバプロでproxypassreverseの設定

## 目的
Nginxでリバプロを構築して、設定する時に少し苦労した。コンテキストパスの設定を行わないと、CSS等が適用されていない様な文字だけのHTMLが表示されてしまう。
今回は、プロキシ遷移先のアプリケーション側で、特にプロキシの設定をする事無く、リバプロが機能するようする。


## 原因
アプリケーションの手前にリバプロを設置した場合に、URLで振り分けを行っている事を前提とする。
例えば、/appにアクセスすると、app.comに遷移。/webにアクセスすると、web.comに遷移する場合を考える。
リダイレクト等が走るとアプリケーションサーバーは/redirectへと遷移させようとするが、この構成の場合は、/app/redirectへと遷移させてほしい。

この様な場合は本来アプリ側が相対パスで指定してくれてるか、プロキシの設定を入れる事で解決する。
今回の場合はアプリ側はいじらないとするので、上記の解決法は使えない。

## TL;DL
``` nginx.conf
events {
    worker_connections  16;
}

http {
    server {
        listen 80;
        server_name localhost;

        location /reveal-docker/ {
            proxy_pass http://reveal-docker:8000/;
            proxy_redirect off;

            set $context "/reveal-docker/";

            proxy_set_header Upgrade             $http_upgrade;
            proxy_set_header Host                $host;
            proxy_set_header X-Real-IP           $remote_addr;
            proxy_set_header X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto   $scheme;
            proxy_set_header X-Forwarded-Host    $http_host;
            proxy_set_header X-Forwarded-Port    $server_port;
            proxy_set_header Accept-Encoding     "";

            sub_filter 'href="/'      'href="$context';
            sub_filter 'src="/'       'src="$context';
            sub_filter 'url("/'       'url("$context';
            sub_filter 'action="/'    'action="$context';
            sub_filter 'href=\'/'     'href=\'$context';
            sub_filter 'src=\'/'      'src=\'$context';
            sub_filter 'url(\'/'      'url(\'$context';
            sub_filter 'action=\'/'   'action=\'$context';
            sub_filter_once off;

            gzip on;
            gzip_vary on;
            gzip_min_length 1000;
            gzip_types text/css text/javascript application/javascript application/xml application/json;
        }
    }
}

```

## 入力箇所

### location
```
 location /reveal-docker/ {
```

### サブディレクトリ
URIの指定を以下で行う
```
set $context "/labweb/";
```

### 遷移先の指定
遷移先のIPアドレスやドメインを指定。今回の場合はコンテナ名を入力した
```
proxy_pass http://reveal-docker:8000/;
```
MacOS、もういい加減複数言語の読み上げに対応しよう、をShortcuts.appで解決する

## 追記:
文章を単語ごとに分解し、それぞれの言語で読み上げるように変更しました。
キーボードショートカット ⌘F5


https://www.icloud.com/shortcuts/241fbd9f59c6466a9201be4024371872

## 目標：
MacOSに複数言語のテキスト読み上げに対応させる。

## 現状：
System Settings - Accesibility - Spoken Content - System Speech Language
で設定した言語で読み上げられる。だから日本語に設定していて"Hello, world"を読ませると、「ハロー！ワールド！」（日本語訛りマシマシ）となって腹がたつ。



![Screenshot 2023-06-10 at 12.43.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/769cad2c-986d-c9ee-2adc-723071d878c3.png)
![Screenshot 2023-06-10 at 12.46.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/42d6c156-b01c-5017-4a97-62413d1d545d.png)

## できたもの：
https://www.icloud.com/shortcuts/de775bec47474a508b66d86d0c2d2346

読み上げコンテンツ　と同じようにテキストを選択して実行するQuick Action。
選択されたテキストから言語を認識し、その発音で朗読する。

キーボードショートカット：　⌘F5

![Screenshot 2023-06-10 at 12.41.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/36654084-45e6-3973-b9c0-d13c61c689a2.png)


![Screenshot 2023-06-10 at 12.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/a038beb4-1f33-1334-65b9-81b7785a6fd6.png)

配布状態では英語日本語中国語に対応している。
新たに対応させたい言語があれば、Shortcutのif文を追加してください。
If文のDetectedLanguage is 言語名

キーボードショートカットの変更は
![Screenshot 2023-06-10 at 12.56.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/b4478c4f-33aa-025e-d8c7-667b48366fc9.png)
MyBatis+Spring Bootでクエリ毎のタイムアウト時間を指定する

通常はコネクションプールの設定でクエリタイムアウトを指定すると思いますが、特定のクエリだけタイムアウト時間を長くしたい！！みたいなケースが稀にあります。本投稿ではMyBatisを使っている場合の指定方法を紹介します。

# バージョン

* MyBatis 3.5.13
* MyBatis Spring Boot 3.0.2
* Spring Boot 3.1.0

# XMLで指定する

SQLをXMLファイルに記載する場合は、 SQLタグの`timeout`属性にタイムアウト時間を指定することができます。

```xml
<select id="select" resultType="int" timeout="30">
  SELECT 1
</select>
```

# アノテーションで指定する

SQLをアノテーションに記載する場合は、 `@Options`の`timeout`属性にタイムアウト時間を指定することができます。

```java
@Options(timeout = 30)
@Select("SELECT 1")
int select();
```


# プロパティで指定する

SQLをXMLファイルに記載する場合は、 SQLタグの`timeout`属性に変数名を指定してプロパティから取得した値を埋め込むこともできます。


```xml
<select id="select" resultType="int" timeout="${timeout.select}">
  SELECT 1
</select>
```

```yaml:application.yml
mybatis:
  configuration:
    variables:
      timeout:
        select: 30 # ★★★
```

`mybatis.configuration.variables`配下に変数(例：`timeout.select`)を指定する。

:::note warn
MyBatis 3.5.13時点ではアノテーションでSQLを記載する場合は、プロパティから取得した値にすることはできません。
:::


# プロパティにデフォルト値を指定する

プロパティ値を埋め込む際に、デフォルト値を指定することもできます。デフォルト値を指定する場合は、MyBatis本体の設定を変更する必要があります。

```xml
<select id="select" resultType="int" timeout="${timeout.select:30}">
  SELECT 1
</select>
```

```yaml:application.yml
mybatis:
  configuration:
    variables:
      org:
        apache:
          ibatis:
            parsing:
              PropertyParser:
                enable-default-value: true # ★★★
```

`mybatis.configuration.variables`配下の`org.apache.ibatis.parsing.PropertyParser.enable-default-value`を`true`にする。


# 参考ページ

* https://mybatis.org/mybatis-3/ja/sqlmap-xml.html
* https://mybatis.org/mybatis-3/ja/configuration.html#properties
Proxmoxのバナーロゴを変更する

# 結論
以下を書き換えるだけです。サイズは**172x30ピクセル**で、透過PNG対応とのこと。
```
/usr/share/pve-manager/images/proxmox_logo.png
```
# 動作確認
背景は透過のほうがデザイン的に良いかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/fcfc58e3-5f08-ffbe-6893-9fe263bd8065.png)

# メモ
VMのブートスプラッシュは容易に変更できないようです。

# 参考にさせていただいたサイト

**Tutorial: Change the Logos and Virtual Machine Boot Screen on Proxmox VE 6.0**
https://www.reddit.com/r/Proxmox/comments/dlfyfm/tutorial_change_the_logos_and_virtual_machine/

**
Flutter：Control+Enterで投稿できるTextField

FlutterのMac/Windows/Linuxにおいて、改行できてかつControl+Enter(またはShift+Enter)で投稿できるTextFieldを作る方法です。検索してもドンピシャな例が意外と見つからなかったので共有します。

※riverpodを使っているのでConsumerWidgetになっています。適宜書き換えてください。

```dart:sample.dart
import 'dart:io' show Platform;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends ConsumerWidget {
  MyHomePage({super.key});
  final TextEditingController _controller = TextEditingController();
  late final _sendMemoNode = FocusNode(onKey: (FocusNode node, RawKeyEvent e) {
    if (e.isControlPressed && e.logicalKey.keyLabel == 'Enter') {
    //shift+Enterにしたいときは e.isShiftPressed にする
      if (e is RawKeyDownEvent) {
        submit();
      }
      return KeyEventResult.handled;
    } else {
      return KeyEventResult.ignored;
    }
  });

  void submit() {
    final text = _controller.text;
    debugPrint(text);
    //ここにSubmitの処理を書く
    _controller.clear();
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      body: Center(
        child: TextField(
            controller: _controller,
            decoration: const InputDecoration(hintText: 'Enter Message'),
            onSubmitted: (_) =>
                {if (Platform.isIOS || Platform.isAndroid) submit()}, //スマホ版では普通にSubmitする
            focusNode: _sendMemoNode,
            keyboardType: TextInputType.multiline,
            minLines: 1,
            maxLines: 20),
      ),
    );
  }
}
```

実行結果↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195465/faab6e73-0afe-6a80-5c3e-79619685538b.png)

Control+Enterを押したときのログ↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195465/e7273f1a-6ba2-29a4-b6c7-4aea2b456526.png)


参考

https://github.com/flutter/flutter/issues/116707
引数の練習

"HAPPY" という文字列を引数で渡した時、
```
＊＊明後日の気分はHAPPYです＊＊
```

とターミナルに表示されるメソッドを作りたい。

呼び出し方はdayaftertommorow_feeling("HAPPY")を使うこと。



こうなる。
```ruby
def dayaftertommorow_feeling(feeling)
  puts "＊＊明後日の気分は#{feeling}です＊＊"
end

dayaftertommorow_feeling("HAPPY")
```

引数を使って、文字列を表示させたいので
dayaftertommorow_feelingメソッドを定義する。
その後引数で渡した文字列を表示したいので文字展開する。
エレキ素人が何か考える（その22）：今さらながらチャタリング

# ボタンチャタリングをオシロスコープで観察
ボタンのチャタリングをオシロスコープで観察したかった、、ただそれだけである。レベルは低いが、エレキ素人ということで勘弁。

## 回路
Arduino互換機を用いた。単純な回路である。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/8780d3a7-20bd-4071-4ea7-7415c4e99aec.png", width=70%>
プルアップ型であり、ボタン押下時はLowとなっている。

## ソースコード
下記ソースコードで、ハンドリングする。
```c++
#define BTN 7

uint32_t t = 0;

void setup() {
  Serial.begin(9600);
  pinMode(BTN, INPUT);
}

void loop() {
  uint32_t p;
  while (!digitalRead(BTN)) {
    if (!t) {
      t = millis();
    }
  }
  if (t) {
    p = millis()-t;
    if (p > 3000) {
      Serial.println("Long Push");
    } else if (p > 500) {
      Serial.println("Short Push");
    } else {
      Serial.println("Very Short Push");
    }
    t = 0;
  }
  delay(10); 
}
```
短押しや長押しで、波形の差があるかを、押していた時間で見分けることにした。ただし、このあたりは、ソフトウェアとハードウエアとの微妙な関連のところであろう。

## デジタルオシロスコープ（OpenScope MZ）
データ（波形など）をPCでハンドリングしたかったため、[OpenScope MZ](https://akizukidenshi.com/catalog/g/gM-12461/)を秋月電子で購入（１万円強）。各種検索結果によると、実は、本製品、不具合などがあるらしい。３−４万円も出せば、安定かつ高機能のPC接続タイプのオシロスコープは存在するが、そこまでの予算もなく、ホビーレベルの用途なのでこの程度で十分と考えた。本製品の情報については、下記サイトに記載あり。
- [OpenScope MZ（本家サイト）](https://digilent.com/reference/reference/instrumentation/openscope-mz/)

## 検証
下記がオシロスコープで取得した波形である。
![WaveFormsLiveChart_2023Apr18_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/2c924deb-e622-b117-ecbc-0deda8802591.png)
![WaveFormsLiveChart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/160f2eae-d378-760e-ee6d-bd983565749e.png)
![WaveFormsLiveChart_2023Apr18_7_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/4a7277f4-0529-c64d-bdde-396e305c67e8.png)

立ち上がりエッジトリガ時の方が、ボタンチャタリングを観察しやすかったが、典型的なチャタリング状態を表しているとは言えるものではなかった。これは、用いたデジタルオシロスコープの分解能（最大サンプリングレート：6.25MHz）に依存するところもあり（やはり高性能が必要か？）。また、ボタンの長押し、短押しによる差異は見受け（感じ）られず。

ボタンの種類により、チャタリングが発生しやすい・しにくい、、といった記事を見かけたことあるが、真偽は不明。機会があれば、トライする。

EOF
Pydanticに6行書き加えるだけで、ArgumentParserと同じ使い方ができるから便利よ、という小ネタ

# この記事について

Pythonのバリデーター（Pydantic）を、Pythonの引数のパーサーとして使う方法を紹介します

**何が嬉しいの？**

- Pydantic以外のOSSライブラリは不要です
- Pythonファイルに渡された引数を検証、型変換させることができます
- Pydanticで定義を書くだけでよいため、ArgumentParserよりも楽です
- IDEの補完が効くようになります

# 方法

BaseModelを継承したクラスに、以下の関数を書き加えます

```python
@classmethod
def parse_args(cls):
    parser = ArgumentParser()
    for k in cls.schema()["properties"].keys():
        parser.add_argument(f"-{k[0:1]}", f"--{k}")
    return cls.parse_obj(parser.parse_args().__dict__)
```

これでpydanticでparse_argsができるようになります

# ソースの例

実際のソースで動きを確認します。

```python:app.py
from argparse import ArgumentParser
from pydantic import BaseModel


class Argments(BaseModel):
    """
        Pythonファイルの引数を定義する
    """
    bucketname: str # AWSのバケット名
    filename: str # ファイル名
    timeout: int # タイムアウト時間

    @classmethod
    def parse_args(cls):
        # 付け足した関数
        parser = ArgumentParser()
        for k in cls.schema()["properties"].keys():
            parser.add_argument(f"-{k[0:1]}", f"--{k}")
        return cls.parse_obj(parser.parse_args().__dict__)


# 実行してみる: 引数を検証する
args = Argments.parse_args()
print(args)
print(args.bucketname)
print(args.timeout)
```

```bash: コマンドプロンプトで実行する
python app.py --bucketname=aws-bucket-contents-name --filename=filekey.json --timeout=123
```

```bash: 実行結果
bucketname='aws-bucket-contents-name' filename='filekey.json' timeout=123
aws-bucket-contents-name
123
```

parse_argsが返す変数は、PydanticのBaseModelを継承した変数です
pythonファイルに渡された引数がデータとして入っていることが確認できます

**嬉しいこと**

Pydanticの型なので、VSCodeの補完の恩恵を受けられます
データ型も定義した型に変換されています

![qiita-image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233180/af3bf21c-8019-a5b8-841f-a5af34ea3330.png)


**検証エラーをさせてみる**

タイムアウトはint型が期待値なので、以下のようにすればエラーになります

```bash: コマンドプロンプトで実行する
python app.py --bucketname=aws-bucket-contents-name --filename=filekey.json --timeout=12.3
```

```bash: 実行結果
pydantic.error_wrappers.ValidationError: 1 validation error for Argments
timeout
  value is not a valid integer (type=type_error.integer)
```

必須になっているファイル名とタイムアウトを渡さないと、エラーになります

```bash: コマンドプロンプトで実行する
python app.py --bucketname=aws-bucket-contents-name
```

```bash: 実行結果
pydantic.error_wrappers.ValidationError: 2 validation errors for Argments
filename
  none is not an allowed value (type=type_error.none.not_allowed)
timeout
  none is not an allowed value (type=type_error.none.not_allowed)
```

必須ではない引数を定義したいときは、Optionalを使います

```python
from typing import Optional


class Argments(BaseModel):
    mail: Optional[str] # メールアドレスは必須ではない
    # 中略
```

この`--mail`は、引数として渡さなくてもエラーになりません
Ansibleコールバックプラグインのメモ

# Ansibleのコールバックプラグイン

##### プレイブックの最後にchangedになったタスク名とホストを表示する

```change_tasks_summary.py
from ansible.plugins.callback import CallbackBase
from ansible.utils.color import stringc

class CallbackModule(CallbackBase):
    CALLBACK_VERSION = 2.0
    CALLBACK_TYPE = 'aggregate'
    CALLBACK_NAME = 'changed_tasks_and_hosts_summary'
    CALLBACK_NEEDS_WHITELIST = True

    def __init__(self):
        super(CallbackModule, self).__init__()
        self.changed_tasks = {}
        self.current_task_name = None

    def v2_playbook_on_task_start(self, task, is_conditional):
        self.current_task_name = task.get_name().strip()

    def v2_runner_on_ok(self, result, **kwargs):
        if result.is_changed():
            host_name = result._host.get_name()
            if self.current_task_name not in self.changed_tasks:
                self.changed_tasks[self.current_task_name] = []

            # ループを使っている場合
            if 'results' in result._result:
                for res in result._result['results']:
                    if res.get('changed', False):
                        item = res.get('item')
                        # 表示形式を変更
                        host_info = f"changed: [{host_name}] => (item={item})"
                        self.changed_tasks[self.current_task_name].append(host_info)
            else:
                # ループを使っていない場合
                if result._result.get('changed', False):
                    # 表示形式を変更
                    host_info = f"changed: [{host_name}]"
                    self.changed_tasks[self.current_task_name].append(host_info)

    def v2_playbook_on_stats(self, stats):
        self._display.banner("Changed Tasks and Hosts Summary")
        for task_name, host_infos in self.changed_tasks.items():
            self._display.display(f"TASK: [{task_name}]")
            for host_info in host_infos:
                changed_text = stringc(f"changed: [{host_info}]", 'yellow')
                self._display.display(changed_text)
```
Go言語のテストで成功したときにGreen、失敗したときにRedで結果を表示したい！(gotest)

## 対象読者
* Go言語で開発を行っている人
* Go標準のテストフレームワーク'testing'を使っている
* テスト結果に色をつけて結果をわかりやすくしたい人
* REDがGREENになることでしか得られない栄養素が欠乏している方

## デフォルトの表示
![スクリーンショット 2023-06-10 11.39.04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510127/b323dc7a-6875-01f8-2011-9be092f69a82.jpeg)

このように結果は全て同じ色で出力するので、ちょっと分かりづらいです。
TDDを行って開発するときは、[RED, GREEN, REFACTOR](https://appkitbox.com/knowledge/test/20130115-367512)というサイクルがとても大事だと思っていますが、
これでは、 WHITE, WHITE, REFACTORとなってしまいます。
REDがGREENになるよろこびがふそくしている!

## 色をつける
こちらのレポジトリのツールを使います
https://github.com/rakyll/gotest

### MacOSでの導入方法
```sh
go install https://github.com/rakyll/gotest@latest
```

### テストの実施方法
```sh
#  -v と -cover はお好みでつけてね
gotest -v -cover
```

### 結果
![スクリーンショット 2023-06-10 11.41.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510127/74c80e31-ae3b-fa0d-0e89-a877b379fde1.jpeg)

これでREDがGREENになることでしか得られない栄養素を獲得できます。
Linuxにnvmを使用してNode.jsをインストールする

1. nvmのダウンロード

```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
```

※ `v0.39.3`の箇所は<a href="https://github.com/nvm-sh/nvm/releases" target="_blank">最新のリリース</a>に合わせて修正する

2. nvmの実行

```bash
. ~/.nvm/nvm.sh
```

3. Node.jsの最新の推奨版をインストール

```bash
nvm install --lts
```

※ バージョンを指定する際は、`nvm ls-remote`コマンドでインストール可能なNode.jsのバージョンを確認し、以下コマンドで指定

```bash
nvm install v20.3.0
```

4. インストールされたNode.jsの確認

```bash
nvm ls
```

```bash
node -v
```
Chainlit の LangChain デフォルト動作をオーバーライドする

# はじめに
LangChain で作ったチェーンやエージェントがあれば, **Chainlit** で簡単にチャット UI を作れます.
(Chainlit については以下に説明を書きましたので, よければご覧ください.)

https://qiita.com/skkzsh/items/17bff703dba27240ec90

チェーンやエージェントさえ作れば, あとはいい感じにやってくれる Chainlit ですが,
いい感じにやってくれるところ (推論実行やメッセージ送信など) をカスタマイズしたい場合があります.

# デフォルト動作をオーバーライドする

そこで, [`langchain_run`](https://docs.chainlit.io/api-reference/langchain/langchain-run) デコレータで, デフォルト動作をオーバーライドできます.

例としてチャット履歴をファイルに保存するようにしてみます.
チャット履歴には [`ChatMessageHistory`](https://python.langchain.com/en/latest/modules/memory/getting_started.html#saving-message-history) クラスを使っています.

:::note warn
なお, Chainlit がいい感じに推論実行やメッセージ送信してた処理をオーバーライドすることになります.
そのため, その処理を変えたくない場合は, 自分で推論実行やメッセージ送信を書いてあげる必要があります.
:::

:::note alert
[0.6.0 で `langchain_run` デコレータは削除](https://docs.chainlit.io/guides/migration/0.6.0)されました.
そのため 0.6 系以降では, 以下のコードは使えません.
:::

```python:my_chat.py
from langchain.memory import ChatMessageHistory
from langchain.schema import messages_to_dict
import chainlit as cl
import json
import my_chain

history = ChatMessageHistory()


@cl.langchain_run
async def run(chain, query: str):
    # チェーンを実行
    answer = await chain.acall(query, callbacks=[cl.AsyncChainlitCallbackHandler()])

    # 実行結果のメッセージを送信
    await cl.Message(content=answer["text"]).send()

    # チャット履歴に User と Chatbot のメッセージを追加
    history.add_user_message(query)
    history.add_ai_message(answer["text"])

    # JSONファイルとして保存
    with open("history.json", "w") as f:
        json.dump(messages_to_dict(history.messages), f, indent=2, ensure_ascii=False)


@cl.langchain_factory(use_async=True)
def factory():
    return my_chain.create_chain()
```

チャットしてみると, ファイルに履歴が保存されるようになっています.

<details><summary>チャット履歴ファイル</summary><div>

```json:history.json
[
  {
    "type": "human",
    "data": {
      "content": "おはよう",
      "additional_kwargs": {},
      "example": false
    }
  },
  {
    "type": "ai",
    "data": {
      "content": "おはようございますやんけ！",
      "additional_kwargs": {},
      "example": false
    }
  },
  {
    "type": "human",
    "data": {
      "content": "おもしろい",
      "additional_kwargs": {},
      "example": false
    }
  },
  {
    "type": "ai",
    "data": {
      "content": "おもろいやん！",
      "additional_kwargs": {},
      "example": false
    }
  },
  {
    "type": "human",
    "data": {
      "content": "ありがとう",
      "additional_kwargs": {},
      "example": false
    }
  },
  {
    "type": "ai",
    "data": {
      "content": "おおきに！",
      "additional_kwargs": {},
      "example": false
    }
  }
]
```
</div></details>

# バージョン情報
- Chainlit 0.3.0
- LangChain 0.0.200
- Python 3.9.16
Welcome to Livebookを一度は読みましょう

はじめに

livebookでx=x+1を複数回評価してもxの値はカウントアップしていかない。

へ～そうなんだ。

livebookは直感的に使えるので、とくに説明も見ず、感覚で使ってたので意外と知らないこと、気づいてないことがありそう。

ということで、「Welcome to Livebook」を読んでみることにしました。

# Welcome to Livebook

Livebookを開いた時に、表示されてるやつです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/4be7e659-13f5-e8af-c679-0e6a204bff5e.png)

# 要点

英語なので流し読みできない私は一通り読んでみました。
気になった点があったら、詳細は、Welcome to Livebook みてみてください。

- Sectionに分けられる。
- 左のメニューの上から二番目を選ぶとSectionの一覧が表示されて、目的のところにジャンプできる
- Sectionの枝分かれ(Branch out fromのボタンを押すと作れる）ができる
- 枝分かれしたSectionで時間のかかる処理をしていても、元のSectionで別の操作をができる（独立したプロセスで実行される）。
- キーボードショートカットの説明
- シークレット（APIキーなど）はLB_で始まる環境変数、セッション、HUBに保存できる
- Markdownの拡張。KaTeXやmermaid記述が使える
- Mixinstallが使える
- Runtimeでほかの分散ノードを接続できる
- defmoduleでモジュールを作って実行したほうが実行速度が速い
- ExUnitを使ったテストを書くこともできる
今更始める機械学習を始めた記録

# 機械学習を学習したの記録

## 学習環境
Minisforum HM90
CPU:Ryzen 4900H
Mem:32GB
SSD:512GB

## セットアップ
[参照URL](https://hidehiko-honda.com/hugging-face-%E3%81%A8-wsl2-%E3%81%A7-%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%ABpc%E3%81%ABai%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89/)
CUDA対応のGPUを積んだり繋いだりできないので、そこだけ飛ばしてます

## 学びのゴール
前提条件：クローズドな環境を構築できる / でーたのろうえいなどをきにしなくてよいじょうきょう
インプット：ソフトウェアやハードウェアの要件や仕様、機能的な説明をテキスト形式のドキュメントで与える
アウトプット：インプットを検証するために必要な手順や条件、機体結果を箇条書きでアウトプットする

## 汎用の仕組みに独自データを付け加える方法


## いま
セットアップが完了するも、そもそも、どうしたらそんなことができるのか？をあさってる。



先達のアドバイスいただけると嬉しいですが、生暖かく見守っていただければ幸いです。
RubyでAtCoder ABC246(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC246のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

# A - Four Points
https://atcoder.jp/contests/abc246/tasks/abc246_a
```ruby:a-246.rb
x1, y1 = gets.split.map(&:to_i)
x2, y2 = gets.split.map(&:to_i)
x3, y3 = gets.split.map(&:to_i)
puts "#{x1 ^ x2 ^ x3} #{y1 ^ y2 ^ y3}"
```
## 解説
排他的論理和を使うことで、答えを求めることができます。

# B - Get Closer
https://atcoder.jp/contests/abc246/tasks/abc246_b
```diff_ruby:b-246.rb
a, b = gets.split.map(&:to_i)
- d = Math.sqrt(a ** 2 + b ** 2)
+ d = Math.hypot(a, b)
puts "#{a / d} #{b / d}"
```
## 解説
求める座標を(x, y)とすると、`a : x = b : y = d : 1`なので、`(x, y) = (a/d, b/d)`が成り立ちます。

# C - Coupon
https://atcoder.jp/contests/abc246/tasks/abc246_c
```ruby:c-246.rb
n, k, x = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)

a.map! do |item|
  used_coupon = [item / x, k].min
  k -= used_coupon
  item - (used_coupon * x )
end
puts a.sum - a.max([k, n].min).sum
```
## 解説
まず、クーポンを最大限使える商品に対してクーポンを使えるだけ使います。そして、クーポンが余っていれば、その数（min(K, N)）だけ割引後の商品の中で価格が高いもの分の価格を除いた商品の価格の総和が答えとなります。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
Rustを極めたい - 2

前回の記事  
https://qiita.com/on_c98/items/db88c333d2e78f30bd8f
# Rustの関数

## 宣言

Rustで関数を宣言する際は`fn`キーワードを用います。

```rust
fn main(){
	foo();
}

fn foo(){
	println!("fooo!!");
}
```

Rustでは、関数の定義する順番（位置）は気にしません。上記の場合、`foo`関数は`main`関数より後に定義されていますが、`main`内で使用することが出来ます。

Rustでは、関数の名前はスネークケース(全て小文字で単語をアンダーバーでつなげる書き方)を使うのが慣習となっています。

```rust
fn snake_case_naming(){}
```

Rustの関数は、引数を受け取ることが出来ます。関数名のカッコ内に`(引数名: 型)`のように記述します。

```rust
fn main(){
	hello("佐藤");
}

fn hello(name: &str) {
	println!("Hello {}", name);
}
```

Rustでは、「デフォルト引数」「オプション引数」と呼ばれるような、省略された場合に既定の値をセットするような機能は、今のところ実装されていません。

また、「可変引数」のような可変長の引数を受け取る関数を定義することもできません。そのような場合は、`println!`のように`マクロ`として実装するか、`Vec`型として受け取ることで疑似的に可変長の引数を実現出来ます。

```rust
fn main(){
	// `vec!`は手軽にVecを作成するマクロです。
	foo("aa", "ii", vec!["uu", "ee", "oo"]);
}

fn foo(first: &str, second: &str, etc: Vec<&str>) {
	println!("first: {}", first);
	println!("second: {}", second);
	for (i, v) in etc.into_iter().enumerate() {
		println!("etc{}: {}", i, v);
	}
}
```

戻り値を返したい場合は、`->`を用いて下記のように記述します。

```rust
fn bar(arg: i32) -> i32 {
	arg * 2
}
```

上記の関数`bar`は、引数で受け取った値を2倍にして返しています。

末尾にセミコロンを付けないとそれは`式（Expression）`として扱われます。Rustでは処理中に`式`が現れた場合、それを戻り値として返します。末尾にセミコロンがついている場合それは`文（statement）`として扱われます。

Rustにおいて、`式`とは「値を返すもの」、`文`は「処理を実行するが値を返さないもの」、となります。

```rust
fn foo() -> i32 {

	// コメントは式でも文でもない
	let z = 4; // 文 statement
	let x = 1 + z; // 文 statement

	bar(); // 文 

	x + 1; // 末尾にセミコロンが付いているので文として扱われる。

	x + 1 // こちらはセミコロンがないので式 expression として扱われる。 foo()関数の戻り値として返される。
}
```

## 最後に

[次回](https://qiita.com/on_c98/items/7abb2f9ce2f5ce3ff8c2)は`if`、`for`、`while`、`loop`について書いていこうと思います。
Cartopy / GDALをWindowsマシンにインストールする

Cartopyをwindowsにpipでインストールしようしてエラーが出てハマったので解決策をメモしておきます。

### 1.Anacondaを使う

どうやらCartopyはAnacondaを使ってインストールすれば何も問題なくインストールできるようです。

いろいろと調べる中でも「Anacondaを使え」という意見がほぼすべてでした。

ただ、私は2020年の有償化以降Anacondaを使うことを避けているので別の方法を探りました。

### 2.Unofficial Windows binaries of cartopyをつかう

Cartopyのドキュメントにそもそも紹介されてはいるのですが、Christoph Gohlkeさんという方が下記のサイトにアンオフィシャルでCartopyのWindows binariesを用意してくれています。

https://www.lfd.uci.edu/~gohlke/pythonlibs/

このページから適当な.whlファイルをダウンロードしてきてインストールします。

私の場合は64bitのWindowsを使っていてpythonのバージョンは3.10を使っているので以下のものをダウンロードしました。

`Cartopy‑0.20.2‑cp310‑cp310‑win_amd64.whl`

ダウンロードしたファイルを適当な場所に持ってきて以下を実行します。

$ pip install Cartopy‑0.20.2‑cp310‑cp310‑win_amd64.whl

これでok。


### 3.GDALのインストールについて

なお、GDALに関しても同様にwindowsにpipでインストールしようしてエラーが出てハマったので上記の2と同じ方法で対処しました。
法線ベクトルを逆行列の転置行列で変換することについて 

# 法線ベクトルの変換

3Dオブジェクトを扱うときは、オブジェクトの回転・変換に合わせてその法線も適切に変換しなければならないときがあります。 
オブジェクトを行列$A$で変換を行う場合、法線$\boldsymbol{n}$ について、 $^t(A^{-1})\boldsymbol{n}$ を変換後の法線ベクトルとして扱えば良いことになりますが、なぜこれで変換後の法線ベクトルが求められるのか示しました。

## 補題
※ベクトル $\boldsymbol{a}$ と $\boldsymbol{b}$ の内積を $(\boldsymbol{a}, \boldsymbol{b})$で表すとする。
$A$ が $(m,n)$ 型の実行列ならば、任意の $n$ 項列ベクトル $\boldsymbol{x}$ および $m$ 項列ベクトル $\boldsymbol{y}$ について

```math
\begin{align}
(A\boldsymbol{x}, \boldsymbol{y}) = (\boldsymbol{x}, ^tA\boldsymbol{y})
\end{align}
```

が成り立つ。
### 補題の証明
証明は、[斎藤線形代数入門](https://www.amazon.co.jp/%E7%B7%9A%E5%9E%8B%E4%BB%A3%E6%95%B0%E5%85%A5%E9%96%80-%E5%9F%BA%E7%A4%8E%E6%95%B0%E5%AD%A61-%E9%BD%8B%E8%97%A4-%E6%AD%A3%E5%BD%A6/dp/4130620010/ref=asc_df_4130620010/?tag=jpgo-22&linkCode=df0&hvadid=295668542764&hvpos=&hvnetw=g&hvrand=7083279410409838105&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009461&hvtargid=pla-526518670770&psc=1&th=1&psc=1)のp63 [6.3]、[定理（転置行列の基本的な性質2）](https://mathlandscape.com/transposed-matrix/)などを参照。

## 本題の証明
$A$ を正則行列、$\boldsymbol{n}$ を法線ベクトル、$\boldsymbol{p}$ を任意のベクトルとする。
このとき補題より以下が成り立つ。  

```math
\begin{align}
(\boldsymbol{n}, \boldsymbol{p}) = (\boldsymbol{n}, A^{-1}A\boldsymbol{p}) = (^t(A^{-1})\boldsymbol{n}, A\boldsymbol{p})
\end{align}
```

$ (\boldsymbol{n}, \boldsymbol{p})=0$ のとき、$(^t(A^{-1})\boldsymbol{n}, A\boldsymbol{p})=0$ だから、$^t(A^{-1})\boldsymbol{n}$ は変換後のオブジェクトに対応する法線ベクトルになっている。
また、
```math
\begin{align}
(\boldsymbol{n}, \boldsymbol{n}) = (^t(A^{-1})\boldsymbol{n}, A\boldsymbol{n}) > 0
\end{align}
```
内積が>0だから、$^t(A^{-1})\boldsymbol{n}$は$A\boldsymbol{n}$と同じ側を向く法線ベクトルになっている。

# 参考
特異値分解による説明
- [法線を正しい向きにするときなぜ逆転置行列なのか](https://qiita.com/ktanoooo/items/7da443e7bc38f7ff6734)
- https://raytracing.hatenablog.com/entry/20130325/1364229762

具体的な計算
- [○○くんのために一所懸命書いたものの結局○○くんの卒業に間に合わなかったGLFW による OpenGL 入門](https://tokoik.github.io/GLFWdraft.pdf) の p202に逆行列の転置行列を求めるくだりがある
DatabricksノートブックからSQLウェアハウスを利用できるようになりました！

Databricksの計算資源には以下の2種類があります。

1. [Databricksクラスター](https://qiita.com/taka_yayoi/items/c5d99cd77fe4bfcf69f0): Python/SQL/R/Scalaを実行できる汎用計算資源です。
1. [SQLウェアハウス](https://qiita.com/taka_yayoi/items/23d7789198c2dcd66381): SQLしか実行できませんが、SQLの処理に最適化されている計算資源です。SQLの処理はこちらを使うのがおすすめです。

DatabricksノートブックではこれまではDatabricksクラスターしか利用できませんでしたが、今回DatabricksノートブックからもSQLウェアハウスを利用できるようになりました！SQLワークロードに取り組んでいる際、SQLノートブックでロジックを記述し、その処理をSQLに最適化されたSQLウェアハウスで実行できるようになります。

マニュアルはこちらです。

https://qiita.com/taka_yayoi/items/141e49b155f4cad1bb34#sql%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%8F%E3%82%A6%E3%82%B9%E3%81%A7%E3%83%8E%E3%83%BC%E3%83%88%E3%83%96%E3%83%83%E3%82%AF%E3%82%92%E4%BD%BF%E3%81%86

> SQLウェアハウスにノートブックがアタッチされている際、SQLとマークダウンのセルを実行することができます。他のすべてのセル(Python、R、その他の言語)は無視されます。SQLウェアハウスで実行されたSQLセルはSQLウェアハウスのクエリー履歴に表示されます。

# SQLウェアハウスの作成

SQLウェアハウスを作成して起動します。
![Screenshot 2023-06-10 at 10.07.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c33695a2-1e2e-e5ea-1966-35349d86e14a.png)

# ノートブックの作成

SQLノートブックを作成します。と言うか、[データブラウザ](https://qiita.com/taka_yayoi/items/1a4f647d4f3817ce2729)も使えるようになってますね。
![Screenshot 2023-06-10 at 10.09.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1e2b740f-19bb-aef0-ed52-93d3ffb0e38f.png)

クラスターセレクターを開くと、SQLウェアハウスを選択できるようになっています。
![Screenshot 2023-06-10 at 10.11.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/609fe476-4782-c488-a651-8e153f2c47c8.png)

SQLウェアハウスにアタッチします。
![Screenshot 2023-06-10 at 10.11.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c9d4b177-75a2-70b8-b175-87a327c5a911.png)

SQLを実行します。
![Screenshot 2023-06-10 at 10.11.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d534b099-c3f9-c182-5d78-0e50b7723788.png)

マークダウンも記述できるので、複雑なSQLロジックを組み立てるのはこちらの方が良さそうです。
![Screenshot 2023-06-10 at 10.11.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7ff4e706-1ff7-0efb-9122-14a966564ebc.png)

ぜひお試しください！

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Spring Bootの@ModelAttributeと@RequestBodyの違い

この記事では、Spring Boot（具体的にはSpring MVC）で使用される`@ModelAttribute`と`@RequestBody`のアノテーションの違いについて解説します。これらはHTTPリクエストからデータを取得するためのアノテーションですが、その使用されるHTTPメソッドと取り扱うデータの種類に違いがあります。

# `@ModelAttribute`

`@ModelAttribute`は一般的にHTTPのGETメソッドで使用されますが、POSTメソッドでも使用可能です。このアノテーションはリクエストパラメータを直接ビューに渡すことを目的としています。これは一般的にフォームデータの送信に使用されます。`@ModelAttribute`を使用すると、リクエストパラメータは直接コマンドオブジェクト（一般的にはJavaBeansやデータクラス）にバインドされます。バインドされるパラメータは通常、クエリストリングやフォームデータに含まれています。

# `@RequestBody`

一方、`@RequestBody`は主にHTTPのPOSTやPUTメソッドで使用されます。リクエストの本文（body）を使用して、Java/Kotlinオブジェクトにデータをバインドします。このアノテーションは一般的にJSONやXMLのようなメッセージボディを使用してデータを送信する際に使用されます。

# 使用例

それぞれの使用例を以下に示します。

## Kotlin側の例:

```kotlin
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api")
class MyController {

    // @ModelAttribute の使用例（POSTメソッドでの使用）
    @PostMapping("/attr")
    fun handleAttribute(@ModelAttribute user: User): String {
        return "Received POST request, user name is ${user.name}"
    }

    // @RequestBody の使用例
    @PostMapping("/body")
    fun handleBody(@RequestBody user: User): String {
        return "Received POST request, user name is ${user.name}"
    }
}

// データクラスの例
data class User(var name: String = "")
```

## Javascript側の例:

```javascript
// @ModelAttribute の使用例（POSTメソッドでの使用）
fetch('/api/attr', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
        name: 'John'
    })
}).then(response => response.text())
.then(data => console.log(data));

// @RequestBody の使用例
fetch('/api/body', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name: 'John' })
}).then(response => response.text())
.then(data => console.log(data));
```

上記の例では、`@ModelAttribute`はPOSTリクエストで使用され、`Content-Type`ヘッダーが`application/x-www-form-urlencoded`と設定されています。ここで、POSTリクエストのボディに`name=John`という形式のデータが含まれており、このデータがUserオブジェクトにバインドされます。一方、`@RequestBody`の例では、JSON形式のデータをPOSTリクエストのボディからUserオブジェクトにバインドします。

これらの違いを理解することで、Spring Bootにおけるリクエストデータの取り扱いがより簡単になります。適切なアノテーションを使用して、あなたのアプリケーションのコードをより効率的に管理することができます。
【React】useStateについて

## はじめに
備忘録がてら、Reactの基礎であるuseStateについて書いていきます。

## useStateとは
useStateは、Reactフレームワークで提供されるフック（Hook）の一つです。useStateフックを使うことで、Reactコンポーネント内で状態（state）を管理することができます。

状態（state）は、コンポーネントが持つデータのことであり、コンポーネント内の変数のようなものです。状態の値が変化すると、Reactは自動的にコンポーネントを再レンダリングしてUIを更新します。

## サンプルコード
このコードで解説していきます。
```
import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [count, setCount] = useState(0);
  const countUp = () => {
    setCount(count + 1);
  };

  return (
    <div className="App">
      <p>{count}</p>
      <button onClick={countUp}>カウントアップ</button>
    </div>
  );
}
```

## 解説
まずは、以下のコードでuseStateを定義します。
```
const [count, setCount] = useState(0);
```
[]内のcountはこの関数の中で使われる変数のようなイメージです。
[]内のsetCountはcountの状態を変化させるための関数です。
useState(0)は、[]内のcountの初期値を設定しています。

```
const countUp = () => {
    setCount(count + 1);
  };

```
この関数で、[]内のsetCount関数を呼び出して、count変数を変化させています。
そして、以下のコードでボタンを押した時に、countUp()を呼び出しています。
```
<p>{count}</p>
<button onClick={countUp}>カウントアップ</button>
```
以上のコードで、ボタンを押すたびに、画面が再レンダリングされ、{count}の変数が1ずつカウントアップしていくはずです。

## 最後に
他にも記事を書いているので、よければご覧ください。

https://qiita.com/hukuryo/items/97797a91d7e2ee0bcabc

https://qiita.com/hukuryo/items/265c676d17fe21e75242

https://qiita.com/hukuryo/items/269457fe06dbba466d3a
Proxmox7 を試してみる　その６　Windows11(create vm)

# Windows11 をインストールしてみる
こちらの記事が大変参考になるのでリンクを紹介。だけですとつまらないので。。。

・[Proxmox VE7.xでwindows11VMを作成する](https://zenn.dev/northeggman/articles/49c6b73c03c81c#qemu%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)

# HDDが32Gだとインストールできない
Windows11の最低HDDインストール要件は52Gらしく、32Gで作成したら怒られました。
Windowsインストール前ならばディスクをリサイズすればよし。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/34540975-c9b1-27a9-e34d-3785a0e99e31.png)

すでにWindowsをインストールした後、ディスクサイズを拡張するのであれば同様にリサイズするが、すでにディスク領域を取られているため若干の手番が必要。

まず、既存のディスクに対して ４G 増分してみます（VMは停止）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/2315fafc-9886-60c7-4231-0fb5cdc65f1b.png)

Windowsを起動し「ディスクの管理」を開きます。４Gが未割当となっているので・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/4ab9ed47-f194-fd8d-0956-29f4192e315f.png)

ボリュームの拡張は隣接するパーティションでないと拡張（結合）できないので、ここは ”AOMEI Partition Assistant 無料版でOK” というソフトを使います。

・[解決済み：Windows 11で「ボリュームの拡張」がグレーで表示されます](https://www.diskpart.com/jp/windows-11/extend-volume-greyed-out-windows-11.html)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/0be41943-a0ad-f6bd-d15f-835d312dd932.png)

# リモートディスクトップが有効にならない
windows11 pro の場合、リモートディスクトップが使えるので（というか proxmoxコンソールでは辛い）有効にしますが、なぜかpinが有効となりログイン拒否されてしまう。

その場合は、いったんpinを削除してローカルアカウントに戻し・・・。としたいが削除がグレーになっているときの解決策。

通知の設定で、”Windows Hello” を オフにすると、pinを削除することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/4dc3f322-f32f-7025-1283-5c342d86966b.png)

# 参考にさせて頂いたサイト様

https://zenn.dev/northeggman/articles/49c6b73c03c81c

https://orebibou.com/ja/home/201611/20161122_001/

https://orebibou.com/ja/home/201610/20161003_001/

https://jp.ext.hp.com/v-ivr/common/os-howto/faq/23/
モデル検証の基本: ホールドアウト法とハイパーパラメーター調整

# ホールドアウト法の語源と定義
ホールドアウト法（Holdout Method）は、「保留する」という意味の英語"hold out"から名前がつけられています。この手法では、全データセットから一部を「保留」し、それをモデル評価のためのテストデータとして利用します。

# ユースケース
あなたはスーパーマーケットの店舗で働いており、様々なデータ（例：曜日、時間、天気、祝日か否か、近くに開催されるイベントの有無など）をもとに、その日の売上を予測するタスクに取り組んでいます。ここではランダムフォレストを選択するケースを考えてみましょう。

ランダムフォレストを選択した上で考えられるハイパーパラメータは「決定木の数」や「各決定木の最大深度」等が考えられますが、これらはモデルが訓練データから自動的に学習できるものではありません。これらのハイパーパラメータは、事前にこちらで設定しなければなりません。

しかしここで問題が生じます。どのハイパーパラメータの組み合わせが最良の結果を生むのか、あらかじめ知ることは困難です。このため、一般的なアプローチは、異なるハイパーパラメータの組み合わせを試し、最良の結果を生む組み合わせを選ぶというものです。これをハイパーパラメータのチューニングと呼びます。

異なるハイパーパラメータの組み合わせを試し、最良の結果を生む組み合わせを見つけることが一般的に行われるハイパーパラメータのチューニングですが、このチューニングには訓練データだけでなく、検証データという別のデータセットが必要となります。なぜなら、モデルが訓練データだけに過度に最適化（過学習）されてしまうと、新たなデータに対する予測性能が下がってしまう可能性があるからです。

そこで利用されるのがホールドアウト法です。（訓練データからハイパーパラメータ検証用のデータを保留する手法）。この手法では、訓練データを用いてモデルの初期学習を行い、検証データを使ってハイパーパラメータのチューニングを行います。この段階でモデルの汎化性能を確認し、最適なハイパーパラメータの組み合わせを見つけることが可能になります。

# 他のデータセット分割手法
ホールドアウト法以外にも、データセットの分割を行う手法はいくつか存在します。これらもまた、モデルの性能評価やハイパーパラメーターの調整に利用されます。主な手法には以下のようなものがあります：

k分割交差検証（k-fold Cross Validation）: データセットをk個の同じ大きさのサブセットに分割し、そのうちの1つをテストデータ、残りのk-1個を訓練データとして用います。これをk回繰り返し、k個全てのサブセットが一度はテストデータとして用いられるようにします。各試行の評価結果の平均を取ることで、モデルの性能を評価します。
これらの手法を適切に利用し、ハイパーパラメーターの調整を行うことで、機械学習モデルの予測性能を最大化することができます
ブロック BLOB、追加 BLOB、ページ BLOB


[ブロック BLOB、追加 BLOB、ページ BLOB について - Azure Storage | Microsoft Learn](https://learn.microsoft.com/ja-jp/rest/api/storageservices/understanding-block-blobs--append-blobs--and-page-blobs)

## ブロック BLOB

> ブロック BLOB は、大量のデータを効率的にアップロードするために最適化されています。 

## 追加 BLOB

> 追加 BLOB はブロックで構成され、追加操作用に最適化されています。 追加 BLOB を変更すると、ブロックは追加ブロック操作を介してのみ BLOB の末尾に 追加 されます。 既存のブロックの更新または削除はサポートされていません。

[AzureFunction経由でBlobにログを書き込む（AppendBlob） - Qiita](https://qiita.com/uzresk/items/b624c5b27cc417694797)


## ページ BLOB

> ページ BLOBは、ランダムな読み取りと書き込みの操作用に最適化された 512 バイトのページのコレクションです。 

> Azure 仮想マシン ディスクは、ページ BLOB によってサポートされます。 Azure には、Premium と Standard の 2 種類の永続ディスク ストレージが用意されています。 


## 参考
[BLOB Storageの概念 - Azure Storage | Microsoft Learn](https://learn.microsoft.com/ja-jp/rest/api/storageservices/blob-service-concepts)

[静的サイトにおけるAzure BLOB Storageの各BLOBの選択について - Qiita](https://qiita.com/changeworld/items/c6f4ca48f4b336c0f6ec)
ElixirでMixの動作を確認してみた

# 概要
ElixirでMixの動作を確認してみました。以下のページを参考にしました。

https://elixirschool.com/ja/lessons/basics/mix

# mixを実行
以下のコマンドを実行しました。
```
$ mix new example
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/example.ex
* creating test
* creating test/test_helper.exs
* creating test/example_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd example
    mix test

Run "mix help" for more commands.
$ ls
example  file  hello.exs
$ cd example/
$ ls
README.md  lib  mix.exs  test
$ emacs mix.exs &
[1] 128098
$ iex -S mix
Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]

Compiling 1 file (.ex)
Generated example app
Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
a
$ mix compile
$ 
```

# まとめ
何かの役に立てばと。
【Git】ブランチの名称を変更する方法


## ローカルブランチ
ローカルブランチのブランチ名を変更するには次のコマンドを実行します。

```terminal
git branch -m 旧ブランチ名 新ブランチ名
```

カレントブランチの名前を変更する場合には次のように実行します。

```terminal
$ git branch -m 新ブランチ名
```

## リモートブランチ

リモートブランチ名を変更する場合には次の手順でコマンドを実行します。

```
$ git branch -m 古いブランチ名 新しいブランチ名
$ git push -u origin HEAD
$ git push origin リモートブランチ名
```
PlatformIOのRP2040でマルチコアする

## 何がしたいのか

Arduino IDEでRP2040は~~嘘みたいだが~~以下のように記述することでマルチコアできる。

```cpp:
void setup(void) {
    // panda
}

void loop(void) {
    // piranha
}


void setup1(void) {
    // samba
}

void loop1(void) {
    // ole!
}

```

これをPlatformIOの`raspberrypi pico`のArduinoフレームワークでやろうとしてもできない。泣いた。

## 解決策

`platformio.ini`をまるっと以下の内容に書き換える。

```ini:platformio.ini
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
```
するとクローンがいろいろ始まっていい感じにビルドできるようになる。

![スクリーンショット 2023-06-09 9.47.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628782/c77e2296-246a-8cb3-30b3-ff3c8a93c476.png)
<sub>がんばれ！</sub>

そうするとなんか動きました。

ディスプレイをSPIで動かそうとしたらマルチコアだと遅くなっちゃった（なんで？）けどI2Cとかは問題なく動いてる。Arduino IDEとの仕様の相違までは調べていないので誰か試した人いたら教えてください。

> **誤解を招きそうなので追記:**<br>
> SPIに関する記述はILI9341モジュールと相性が悪かったよーってだけで、SPI雑魚とかの悪口を言ってるわけじゃないです。PlatformIOだから遅くなったとかじゃなくて単純に仕様なのかも。要約するとあんまり気にしなくていいです。

## おわりに

おわりです。