OmniAICreator/Qiita-1.07M huggingface dataset:
【Azure AI Search】Custom Vectorizer として使用する Web API の入出力

# 注意事項

- Azure AI Search におけるインデックスの作成・更新に関する REST API では，API バージョンが `2023-10-01-preview` の際に，ベクトル検索の構成オプションを `vectorSearch` キー内で指定でき，そこで任意の Web API を Custom Vectorizer として登録できますが，その Web API の入出力に関するメモです．（下の `my-custom-vectorizer` 部分に関して）

```json
{
  ...
  "vectorSearch": {
    "algorithms": {...},
    "profiles": {...},
    "vectorizers": [
      {
        "name": "my-aoai-vectorizer",
        "kind": "azureOpenAI",
        "azureOpenAIParameters": {
          "resourceUri": "https://<my-azure-openai-resource>.openai.azure.com",
          "deploymentId": "<my-text-embedding-model>",
          "apiKey": "<my-azure-openai-api-key>"
        }
      },
      {
        "name": "my-custom-vectorizer",
        "kind": "customWebApi",
        "customVectorizerParameters": {
          "uri": "https://<my-custom-vectorizer-endpoint>",
          "httpMethod": "POST"
        }
      }
    ]
  }
}
```

# 心の声

- 正しい出力形式がわかるまでそれなりに時間がかかりました...（公式ドキュメントは見つけられていないため，ご存じの方は教えてください）

# ポイント

- 基本的に入出力は Custom Skill と同様です．
  - Embedding の対象となるテキストは `values[].data.text` にあります．
  - 最終的に Embedding は `values[].data.vector` に格納する必要があります．

# リクエストボディ例

```json
{
  "values": [
    {
      "recordId": "0",
      "data": {
        "text": "公式ドキュメントは見つけられていないため，ご存じの方は教えてください"
      }
    }
  ]
}
```

# レスポンスボディ例

```json
{
  "values": [
    {
      "recordId": "0",
      "data": {
        "vector": [0.0, 0.0, 0.0, 0.0, 0.0, ...]
      }
    }
  ]
}
```
vs1053bをスタンドアロンで使ってみた

qiitaを眺めていたところ、以下の記事を見つけました。

https://qiita.com/ain1084/items/0dab92f5d073f6f188ac

以前秋月の処分品でvs1053bのDIP化基板モジュールを購入して部品箱にしまってあって、使い道を考えていたのですが、手持ちの部品で作れて、ちょうどいい感じです。

2023年暮れの時点でこの処分品は在庫がまだあり、チップのみが700円に対してDIP化基板モジュールが420円ととってもお徳です。

追記：2024/7に秋葉原のお店の二階で在庫処分特価で200円になっていました。私が見た時には100枚くらいはあったと思います。

Amazonでもvs1053bを使ったモジュールは千円以上します。

ブレークアウト基板より単体チップのほうが配線は面倒ですが、融通がききます。

いろいろ思案して両面のユニバーサル基板を使うことも考えたのですが、表面にジャンパーを張るためには片面のほうが都合がよいです。また変換基板が大きく、部品も多いので、秋月のC基板では無理で大きなユニバーサル基板にしました。

vs1053bの電源は1.8v+2.8vが標準ですが、1.8v+3.3vでも動作可能です。SDカードが3.3vなので、この組み合わせにします。1.8vをLM317(100mA)で作り、3.3vをXC6202(150mA)で作る事にします。LM317は220Ω,100Ωにしました。

電源は5Vにしました。これはこれまで作ったDACのI2Sにそのまま送り出せるからです。

Adafruitのブレークアウト基板を参考にして、AVCCとIOVCCの間と、AGNDとGNDの間にはおまじないにフェライトビーズを入れてあります。

ストックしてあったSDカードソケットは裏にボッチが二つあり、一つは基板の穴に入れて、片方が入るようにユニバーサル基板に穴を開けてはめ込み、四隅をジャンパーにハンダ付けして固定しています。

DIP化基板モジュールは交換することなどないためソケットなどは使わず、直にユニバーサル基板にハンダ付けしました。足が邪魔にならないように少し浮かせた状態で付けてあります。

ピンヘッダーを短く切ってもいいかもしれませんが太いやつを48本もきるのはちょっと面倒です。

vs1053bにはI2S出力があり、スタンドアロンでも使えるので、いつものI2Sコネクタも用意しておきます。

12.288MHzの水晶は[部品取り](https://qiita.com/yamori813/items/a5dd6606efa91506f981)したものを使いました。パッケージには12.2EF7Nとしか書いてありませんが、周波数カウンターでI2Sのマスタークロックを見たところちゃんんと12.288MHz近くになっていました。

SPI flashはたくさんストックがあるのですが、なにかのジャンクから発掘され1MバイトとFreeBSDでは使い道のなかったMX25L8005を変換基板に貼り付けて、基板用リードフレームで足を生やします。チップが汚れていて、間違えて逆につけてしまいました。

![IMG_20231230_094902.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/98f3ab57-b17f-f97a-4560-f1f5bf2ef68c.jpeg)

flashは当初ファイルをコピーしてMacのflashromで焼いていたのですが、なかなかうまくいかなかったので、VSIDEから焼くようにしました。

VSIDEから焼く時は、bootのジャンパーを外してSDカードを抜いて電源を入れてVSIDEのPrommer/Flash Utilityを開きます。

1Mバイトも必要ないので、128KバイトのST 25P10VPに変えました。

VSIDEでCOMポートを変更するダイアログはstartした後にターゲットが見つからないと開けるのですが、COMポートは8までしか設定できず、USB FTDIのチップはCOM23になっていたので、solutionファイルを秀丸で開いて編集しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/ae744c9b-c1ba-1333-d135-8cb6826786df.png)

デバッグログは9600bpsで確認できます。

ヘッドフォン端子はつけないつもりだったのですが、確認を簡単にできるようにつけました。

再生が出来るようになったのですが、音がおかしいです。

VSDSPの掲示板に書き込んだところ、もうお休みにも関わらずコメントをもらえました。SCI_CLOCKFがおかしいということのようです。

http://www.vsdsp-forum.com/phpbb/viewtopic.php?p=16015&sid=f6c8e356ee880e46de31722a44cca182#p16015

なんからの理由で、SCI_CLOCKFが正常に設定されないようです。

またMyMain()の中で強制的に設定する方法を試したところ、最初はうまくいきませんでした。

これはplayer.imgを指定して焼いていても実際に焼かれるのはeeprom.imgでこれがrecoder.imgから作られた物が残っていて、変更が反映されないためでした。

当初チップのバグなどを疑いましたが、VSIDEのビルドに起因する問題のようです。VSIDEはv2.48でした。

どうにかちゃんと鳴るようになりました。

I2S接続のFN1242,PCM5102は鳴りましたが、PCM1795はだめでした。DAC側の問題でしょうか？

UIを作れるほどメモリなどに余裕はないと思われ、UI部分だけ外部で処理するのがよさそうです。方法を考えてみたいと思います。

ちょっと古いですが、データシートを翻訳された方がいました。

https://www.chiaki.cc/Timpy/vs1053b_jp.html

MP3のプレーヤーであればESP32単体でも作れるようですがESP32のI2Sにはマスタークロックがなく、FN1242などのDACが使えないので、マスタークロックがあるvs1053bは貴重です。

FreeBSDのAtherosでもmpg123を動かしてmp3を再生できますが、vs1053bの方がお手軽です。ネットのストリームはmpg123でメディア(SDカード)はvs1053bと使い分けるのが良さそうです。

9600bpsのシリアル接続で制御可能でstandalon.pdfにはPlaying modeとFile modeというの書いてあります。通常はPlaying modeでfキーを入力した後、曲が終了したところでFile modeになります。File modeのプロンプト>になり、^jを入れたところで処理されます。Playing modeはPlayCurrentFile()の実行中にUserHook()で処理され、File modeはMyMain()の中で処理されています。

消費電流はSDカードにもよるのかもしれませんが、単体で40mA以下で、FN1242をつないだ時に60mAくらいでした。
Officeスクリプトでの自動化について

仕事でOfficeスクリプトに触る機会があったので調べたことをまとめていきます



OfficeスクリプトとはOffice365で使える自動化の手法です
Excelの自動化といえばVBAを思いつきますが WEB版のExcelでも自動化できるのがOfficeスクリプトです

Excelの「自動化」タブから操作が可能です

ブラウザ上で「自動化」タブが出ない場合はリボンのレイアウトからリボンをカスタマイズすることで表示されます
もしリボンのカスタマイズが表示されない場合は管理者に制限されていることがあるそうです

私も表示されませんでしたが、デスクトップアプリで開いた場合は表示されたため、デスクトップアプリで開いています


基本的なコードとしては
各スクリプトには最初のパラメーターとして ExcelScript.Workbook 型の main 関数を含める必要があります

関数を実行すると、Excel アプリケーションはブックを最初のパラメーターとして指定して、この main 関数を呼び出します

OfficeスクリプトはTypeScriptで書かれています
JavaScriptの上位互換の言語のためJavaScriptの知識があると読み書きしやすいそうです
私はJavaScript未学習のためこの機に基本を勉強しました

変数の宣言には以下の3つがよく使われます
var 変数名: 型名
let 変数名: 型名
const 変数名: 型名

varは再宣言、再代入が可能です
スコープはブロックに関係ないので別ブロックでも適用されます

letは再宣言が禁止、再代入は可能です
constは再宣言、再代入ともに禁止です
let、constのスコープはブロック内のみのため他のブロックで同じ変数名を使っても再代入されません

以下のコードでログメッセージを出力することができます
console.log()


自動化できる内容としては
調べてみたところ別のブックの操作などはPower Automateも使用しないとできないようです
処理の範囲はVBAの方が広いんじゃないかと思います

 WEB版のExcelで単一ブック内の作業をするのであれば自動化を検討してもいいかもしれません
C#:透明な背景を指定したいときのエラー

# C#:透明な背景を指定したいときのエラー

```C
System.ArgumentException: 'コントロールは透明な背景色をサポートしません。'
```

## 原因

```C#
this.BackColor = Color.FromArgb(80, 0, 0, 0); // 半透明
```
`BackColor`の指定ではできない


## 解決

```C#
this.Opacity = 0.3;
```
`Opacity`で指定する。
GitLab Duo Chatに聞いてみた - 要件定義のコツは？

# いまさらそれ聞く？ 要件定義のやり方、おしえてちょ

さて、どんなときでも、基本に立ち返って、振り返るというのは大事なことですよね。
でも、そこそこの立場で、そこそこの給料もらえる？ようになったら、バカなことはもう聞けません。

でも！

相手がAIなら、いつでも「いまさら？」な質問ができるので、GitLab Duo Chat相手に、はぁ？な質問をしてみました。

# 「要件定義するとき、どんなことに気をつけたらいいの？」

こんな感じで日本語で聞いてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/d419743f-350f-ff12-ac07-3deeb19d71a1.png)

ほぉほぉ。めっちゃ当たり前ですけど、これだけで、大まかな重要チェックポイントが掴めましたね。

そうそう、途中、「日本語で受け付けられません」みたいなことを言われたときは、

/reset

や

/clean

を打ち込んでから、日本語で書くと理解してくれるっぽいです。
(IMEのエンターキーを、"入力"と判定してしまうという、バグがありますが、、。気をつけてください)

## Q1.ユーザーのニーズをしっかり汲み取るとは？

わかってはいますが、詳細をつっこんで聞いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/1afbbba6-4db3-7329-f80f-eae10eaff4ff.png)

さようですか。たしかに。身に沁みます。

## Q2.要件の詳細に書くとは？

詳細って、なにをどこまで聞けばいいのかなって思いますよね。重箱の隅なんて、いくらでも突っつけますから。バランス感覚ってどんな感じなんでしょ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/1433020d-9d8c-c63b-0224-dac0243e8bac.png)


## Q3. 実現可能な要件かを検討・・・て？

そんなの、気合いがあれば、なんでも作れると思いますが、、、一応聞いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/766f1783-95c7-dd9d-8ab4-66a19e3f6c56.png)

そっか・・・スケジュール。徹夜しまくればいいと思ってましたけど、みんながみんなそんなことするわけないですし、仕事に命かけてる人って、そんなに多くはない・・？でしょうし。

メンバーの"平均感覚"を考えてスケジューリングしないと、チームが破綻するんだろうな、とふと思いました。

## Q4. 要件の優先順位をつける、とは？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/25006615-da55-f9d7-0d77-0431b8132fdd.png)

おお、優先順位マップ。それと、優先順位の見直し。
ドッキーン！ こういうの、発注元の人たちの頭にぶち込んでやりたいと思ったのは私だけでしょうか。

## Q5. 柔軟な設計を心がけるって？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/61a56fc3-4c83-9ddf-ca55-b3c97f5f7dc1.png)

おーっと。さっき、詳細を書けって言われてましたけど、今度は詳細を書きすぎるなと・・・？
そんな矛盾したことを言ってるわけがないと思うので、ここはちょっと頭をひねってみる・・・。

つまりは、要件をヒアリングしているときに、ゆるめにしておいたほうがいいところと、詳細を詰めておいたほうがいい部分がある、ので、それを見逃すな、ということに違いない。
こういうのって、やっぱり複数人でレビューし合って、責任を分担?しておくのが無難な気がしてきた。

## Q6. 要件定義書を作成、って。ま、聞かなくても分かる気が。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/1ed27ff1-4ef9-7dfb-fe9b-69309a5dcd68.png)

おっと、ちょっと意外に、いろいろな指摘をもらってしまった。

### (おまけ) せっかくなので、要件定義書の目次を教えてもらおう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/06d7f8b6-31fb-8813-ac5c-9fea88ceacaa.png)

ほぉほぉ。やっぱ、そんな感じだよねー。と。ここで、データモデル図をラフでも考えておけば、あとで無理難題な要件が出てきたときに、さすがにいまからそれ無理です、みたいなことが説明しやすくなるんだろうなー。と思ってしまった。
画面イメージ図もある程度書いておいて、当初の設計から外れすぎないようにしておかないといけないですね。

## Q7. 要件の定期的な見直しとは？

聞かなくてもわかる気がするが、聞いてみよう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325737/8d4cf370-0e3a-329a-eb39-b589c0837417.png)

おっと！ Requirements機能？ 微妙に使い方がわからん、という人と遭遇したことがあるが、ここで、GitLab Duo Chatちゃんにオススメされたぞ・・・。よし、これは今後のブログネタにしよう。

# というわけで

GitLab Duo Chatは、ソフトウェア開発におけるいろんな質問や悩みを相談できる相手になりえそうな感じがしてきましたね。

へー。なんか今後が楽しみ。

それと、今日は、改めて頭が整理できた日でした。
よし、今後はいろいろ聞いてみよう！

ばははーい。
Difftasticは求められていたdiffなのか?

:::note info
この記事は、pixivFANBOXに平日毎日書いている記事のうち、未公開のものを１つ先出しで公開したものです。
https://kinneko.fanbox.cc/
:::

　Difftasticというツールがあるというのを知った。Rustで書かれたdiffコマンドの代替ツール。
 
　　Difftastic, a structural diff
　　https://difftastic.wilfred.me.uk/
  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/ba7364b8-9171-672f-caf5-d05ebc3b5d71.png)

  　普通のdiffは行ごとの違いを分析して提示するので、うまく差分が取れないことや、理解できない断片だけを提示してくることもある。また、書式フォーマットが変わるのにも弱い。たとえば、タブを変更したらみんな違うと認識してしまう。さらに、ブロックでの大きな変更に弱い傾向があると思う。あくまで、近い行のまわりで何かがあるような場合に便利なだけ。でも、ずっと使われてきている。

　Difftasticのドキュメントの例では、普通のdiffはこんな感じ。
 
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/89172b90-1e25-d08e-579e-dc997f695068.png)
 
 　Difftasticでは、構文に基づいたファイル比較をしてくれるらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/66f4d909-5063-5576-e6ac-13fd6887a53b.png)

　多くのプログラム言語や、データフォーマットに対応している。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/e9a98763-b5c0-564f-b45c-3dded0c37287.png)

　GIT_EXTERNAL_DIFFや.gitconfigに設定することで、gitから使うこともできる。

　　Git - Difftastic Manual
　　https://difftastic.wilfred.me.uk/git.html

　macOSでも動くようなので、入れてみる。

　ソースはこちら。

　　Wilfred/difftastic: a structural diff that understands syntax 🟥🟩
　　https://github.com/Wilfred/difftastic
  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/bc12deec-66d7-6b46-a621-e90b33f70060.png)

　インストール方法はこちら。macOSではbrewで入るみたい。

　　Installation - Difftastic Manual
　　https://difftastic.wilfred.me.uk/installation.html

　これで入れてみたけど、依存関係のあるライブラリなど大量にビルドするので時間がかかる。

 　Homebrewで自前ビルドしなくても、ビルド済みのあるじゃん...

  　　Releases · Wilfred/difftastic
　　https://github.com/Wilfred/difftastic/releases
  
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/a35a70e3-7299-f229-c96f-eca6b99b3293.png)

　difft-aarch64-apple-darwin.tar.gzをダウンロードして展開してみる。

```
% ls -alh difft
-rwxr-xr-x@ 1 kinneko  staff    67M 11 26 10:20 difft
```

　macOSなので、コマンドといえど、そのまますぐには実行できない。

```
% ./difft --help
zsh: killed     ./difft --help
```

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/fec8be5d-e6ab-a935-9f84-939c3d9304d7.png">

　FinderからCtrクリックで開くを選ぶ。

 <img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/1dfe85a9-0e5a-4f15-f8c2-33da882fb0a1.png">

　開くを押すとterminalで起動する。普通に動くようだ。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/af894721-e208-014f-97f4-4155d509aabf.png)

　実行できるようになった。ライブラリ類での不整合があるわけではないみたい。
　なので、brewから入れる必要はまったくないということか... 依存関係でゴミをいっぱい入れてしまったなぁ...
　待てよ？ brewで入れたライブラリがあるから動いているのかもしれないな... もう確認できないけどw

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1513/1c0a4c43-7a86-aac2-2930-8c14590dc6e7.png)

　あとは、/usr/local/binにコピーして使えばよさげ。

```
% sudo cp difft /usr/local/bin/
```

　パス的には、brewで入れたもののほうが早いらしいw

```
% which difft
/opt/homebrew/bin/difft
```

　なんか入れただけで飽きたw

　タイトルの疑問は未解決だけど、たぶん、きっと誰かが、Qiitaで使った感想とかを書いてくれるに違いない。

　とはいえ、既存のツールのpatchとかquiltにはdiffは相変わらず必要なので、差分閲覧専用のツールといった感じ。すぐには完全な代替えにはならないだろう。
Rocky Linux で使用されるネットワーク設定に関連するコマンド

1. **`nmcli`**
   - ネットワークデバイスの一覧表示: `nmcli device status`
   - 利用可能なWi-Fiネットワークのリスト表示: `nmcli dev wifi list`
   - 新しいWi-Fi接続の作成: `nmcli dev wifi connect [SSID名] password [パスワード]`

2. **`nmtui`**
   - インタラクティブなテキストインターフェースの起動: `nmtui`
   - ここからネットワークの接続設定や編集が可能です。

3. **`ifconfig`**
   - インターフェースの設定情報表示: `ifconfig`
   - 特定のインターフェース（例：eth0）のIPアドレス設定: `ifconfig eth0 192.168.1.2 netmask 255.255.255.0 up`

4. **`ip`**
   - インターフェースの一覧表示: `ip link show`
   - 特定のインターフェース（例：eth0）のIPアドレス設定: `ip addr add 192.168.1.2/24 dev eth0`

5. **`route`**
   - ルーティングテーブルの表示: `route -n`
   - 新しいルートの追加: `route add -net 192.168.2.0 netmask 255.255.255.0 gw 192.168.1.1`

6. **`netstat`**
   - アクティブな接続の表示: `netstat -ant`
   - リッスン中のポートの表示: `netstat -tuln`

7. **`ss`**
   - アクティブなTCP接続の表示: `ss -t -a`
   - サーバー上のリッスン中のポート表示: `ss -ltn`

8. **`iwconfig`**
   - ワイヤレスインターフェースの設定情報表示: `iwconfig`
   - 特定のワイヤレスインターフェース（例：wlan0）のESSID設定: `iwconfig wlan0 essid [SSID名]`

9. **`ping`**
   - ネットワークホスト（例：google.com）への接続テスト: `ping google.com`

10. **`traceroute`**
    - パケットが目的地までの経路表示: `traceroute google.com`
StringBuilderとString型の違い　-LeetCode Merge Strings Alternately使用

## 問題文
2 つの文字列 word1 と word2 が与えられます。 word1 から始めて交互に文字を追加して、文字列を結合します。ある文字列が他の文字列より長い場合は、マージされた文字列の末尾に追加の文字を追加します。

マージされた文字列を返します。

## 解き方 3つ
### コード① StringBuilderを使用しない 実行速度：13ms　メモリー：42.82MB
```java
class Solution {
    public String mergeAlternately(String word1, String word2) {
        String ans ="";
        int index=0;
        while(index < word1.length()+word2.length() ){
            if(index < word1.length()){
                ans += word1.charAt(index);
            }
            
            if(index < word2.length()){
                ans += word2.charAt(index);
            }
            index++;
        }
        return ans;
    }
}
```
### コード②　StringBuilder使用する 実行速度：2ms　メモリー：42.08MB
```java
class Solution {
    public String mergeAlternately(String word1, String word2) {
        int index=0;
         StringBuilder str = new StringBuilder();
        while(index < word1.length()+word2.length() ){
            if(index < word1.length()){
               str.append(word1.charAt(index));
            }
            
            if(index < word2.length()){
                    str.append(word2.charAt(index));
            }
            index++;
        }
        return str.toString();
    }
}
```

### コード③　StringBuilderとMath.max,三項演算子を使用 実行速度：2ms　メモリー：41.72MB
```java
class Solution {
    public String mergeAlternately(String word1, String word2) {
        int index=0;
         StringBuilder str = new StringBuilder();
         int maxLength = Math.max(word1.length(),word2.length());

        while(index < maxLength){
            char w1 = (index < word1.length())? word1.charAt(index) : '\0';
            char w2 = (index < word2.length())? word2.charAt(index) : '\0';

            if(w1 != '\0'){
               str.append(w1);
            }
            
             if(w2 != '\0'){
                    str.append(w2);
            }
            index++;
        }
        return str.toString();
    }
}
```

## 結果
StringBuilderを使用するかしないかで実行時間が11ms減らすことができた

## StringBuilderとString型の違い
String型は不変です。そのため+=で文字を追加した場合は、新しいString型のインスタンスが生成され、パフォーマンスがコード①のように低いものになります。一方で、StringBuilderは可変型です。文字を追加したとしても新しいインスタンスが生成されることはなく、String型のようにパフォーマンスを下げることはありません。

StringBuilderクラスには文字列から検索をかけるメソッドがないため、String型に変換する必要があります。また、変更数が少ない場合はパフォーマンスに違いがあまり見られないため、String型でも良いかもしれません。

このことから、StringBuilderを使用する場合は、文字列に対して多くの変更を行うことが予測される場合か文字列に不明な数の変更を加えると予想される場合。

## 参考
https://learn.microsoft.com/ja-jp/dotnet/api/system.text.stringbuilder?view=net-8.0
[Swift]むりやりPoint-Free Style

# Point-Free Styleとは
関数を渡す関数を使う時にTrailing closureやクロージャ式を使わず関数の識別名を渡すスタイルのことです。
たとえば
```swift
func add2(_ i: Int) -> Int {
    i + 2
}
```
という関数を配列内の全てに適用する時に
```swift
intArray.map { add2($0) }
// または
intArray.map( { add2($0) } )
```

と書くかわりに
```swift
intArray.map(add2)
```
と書くスタイルです。

こちらもPoint-Free Styleです。
```swift
// 全ての要素を足し合わせる
intArray.reduce(0, +)
```

# 引数のメソッドを使いたい
ところが引数のメソッドを使いたい場合通常のやり方ではPoint-Free Styleが使えません。
```swift
// 全ての要素が偶数かどうか
intArray.allSatisfy { $0.isMultiple(of: 2) }
```
# むりやり使うための知識
## Swiftのメソッドの型
Swiftの関数には型が存在します。たとえば先ほどの`add2`関数の型は`(Int) -> Int`です。
```swift
func add2(_ i: Int) -> Int {
    return i + 2
}

print(type(of: add2)
// prints (Int) -> Int
```
ではメソッドの型はどうなっているでしょう。
```swift
print(type(of: 0.isMultiple))
// print (Int) -> Bool
```
これも関数と同じ形式の型になっています。
ところがメソッドにはもう一つの取り出し方があります。
```swift
print(type(of: Int.isMultiple))
// print (Int) -> (Int) -> Bool
```
`型名`.`メソッド名`という形で取り出すことで、インスタンスを引数にとりそのインスタンスがもつメソッドと同形の関数を返す関数として取り出せます。

```swift
let method = Int.isMultiple

let methodForOne = method(1) // 1.isMultiple と同じ
print(methodForOne(2))  // 1.isMultiple(of: 2) と同じ
// prints false

// あるいは
print( method(1)(2) )
// prints false
```
## 引数の順番を入れ替える
これを使えばPoint-Free Styleを使えそうです。
しかし、引数の順番が逆なのでこれを入れ替える関数が必要です。
```swift
func flip<A, B, C>(_ f: @escaping (A) -> (B) -> C) -> (B) -> (A) -> C {
    { b in { a in f(a)(b) } }
}
```

# むりやりPoint-Free Style
準備が整いました。先ほど出した例をむりやりPoint-Free Styleで書いてみましょう。

元の形
```swift
// 全ての要素が偶数かどうか
intArray.allSatisfy { $0.isMultiple(of: 2) }
```

むりやりPoint-Free Style
```swift
intArray.allSatisfy(flip(Int.isMultiple)(2))
```

# まとめ
これで引数のメソッドを利用したい時でもPoint-Free Styleで書くことができるようになりました。
ほかにもむりやりPoint-Free Styleはあるはずです。これはPoint-Free Styleは無理とあきらめずに探しだしてみましょう。
変な奴と後ろ指さされること間違いなしです。

# 追記
問題点があったので追記です。
## 問題点
引数を持たないメソッドの場合`flip`関数が使えない。

以下のような場合です。

```swift
// struct Int {
//  func signum()
// }

intArray.map(flip(Int.signum)())  // コンパイルエラー
```

## 対応
以下のような関数を作ります。
```swift
func shrink<A, B>(_ f: @escaping (A) -> () -> B) -> (A) -> B {
  { a in f(a)() }
}
```

```swift
intArray.map(shrink(Int.signum))  // OK
```
wasm-packのHeadless Chromeでのテストでエラーが出る

## 概要
[Rustを使ったWebAssemblyアプリケーション作成のチュートリアル](https://rustwasm.github.io/docs/book/game-of-life/testing.html) を進めていて、
テスト実行のフェーズでエラーが出た。
エラーの回避策を調べたのでメモ。

実行したコマンドは以下：
```sh
wasm-pack test --chrome --headless
```
コマンド実行時のログから、
エラーと関係ありそうな部分を抜粋：
```
...
Running headless tests in Chrome on `http://128.0.0.1:51208/`
Try find `webdriver.json` for configure browser's capabilities: 
Not found
Starting new webdriver session...
DevTools listening on ws://127.0.0.1:51211/devtools/browser/f19b9d6c-9049-4152-be3d-1b6867d9a666
driver status: exit code: 1
driver stdout:
    Starting ChromeDriver 114.0.5735.90 (386bc09e8f4f2e025eddae123f36f6263096ae49-refs/branch-heads/5735@{#1052}) on port 51208 
    Only local connections are allowed.
    Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
    ChromeDriver was started successfully.
...
Error: Running Wasm tests with wasm-bindgen-test failed
Caused by: Running Wasm tests with wasm-bindgen-test failed     
Caused by: failed to execute `cargo test`: exited with exit code: 1
  full command: "cargo" "test" "--target" "wasm32-unknown-unknown"
```

## 原因
`ChromeDriver`と`Chrome`のバージョンに互換性がないため。

##  回避策
ChromeDriverのインストール方法はこちらを参考にした。
[Chrome Driverのインストール方法 (zenn.dev)](https://zenn.dev/ryo427/articles/7ff77a86a2d86a)

適切なバージョンのChromeDriverをインストールする。
[ChromeDriver - WebDriver for Chrome - Downloads (chromium.org)](https://chromedriver.chromium.org/downloads)
ダウンロードしたらPATHの通っているところに配置すること。

##  参考資料
[Testing Life - Rust and WebAssembly (rustwasm.github.io)](https://rustwasm.github.io/docs/book/game-of-life/testing.html)
[Headless Chrome test fails · Issue #611 · rustwasm/wasm-pack · GitHub](https://github.com/rustwasm/wasm-pack/issues/611)
[Chrome Driverのインストール方法 (zenn.dev)](https://zenn.dev/ryo427/articles/7ff77a86a2d86a)
SQLAlchemyを使用してCloudSQLに接続する方法

## はじめに
SQLAlchemyを使用してCloudSQLと接続するのに手こずったのでその方法についてのメモです．

:::note warn
CloudRunでデプロイした際にCloudSQLに接続したことを元に記事にしたものです．
:::



## MySQLに接続するためのパッケージ
PythonでMySQLに接続するためのパッケージは色々ありますが，今回はPyMySQLを使用します．

**インストール**
```bash
pip install PyMySQL
```

## インスタンスの作成
まず，CloudSQLのコンソールに移動してインスタンスを作成します．SQLの種類は以下の３つから選べます．

![スクリーンショット 2023-12-29 18.04.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630894/0c5f2d37-6152-c38b-1f5f-23eb16c6bfef.png)

今回はMySQLを使用します．
使用したいSQLを選択してインスタンス情報を設定してください．
接続が目的なので細かい設定については今回は触れません．

:::note info
Compute Engine APIが有効になってない場合は有効にしてください．
:::


:::note info
rootユーザのパスワードは後ほど使用します．メモなど残しておいてください．
:::

インスタンスが作成できたら，サイドバーのデータベースを選択してデータベースを作成します．この時作成したデータベース名も接続の時に使用します．（これは確認できるのでメモに残さなくても大丈夫）


## データベースと接続
**データベース接続に必要な情報**
- データベースのユーザ名（root）
- ユーザのパスワード
- データベース名
- 接続名

![スクリーンショット 2023-12-29 18.46.05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630894/08ab3ec7-36a5-6c63-161b-2eb0609bab2a.jpeg)


**データベースエンジンの作成**
```python
from sqlalchemy import create_engine

# データベースエンジンの作成
DATABASE_URL = f"mysql+pymysql://{ユーザ名}:{パスワード}@/{データベース名}?unix_socket=/cloudsql/{接続名}"
engine = create_engine(DATABASE_URL, echo=True)
```
これ以外は，データベースをSQLAlchmeyで使う時と同じで大丈夫です．
SQLAlchemyに関しては，また別で記事を書く予定です．

## おまけ
自分が使用したディレクトリ構成とソースコード載せておきます．

**ディレクトリ構成**
```bash
db_dir
├── __init__.py
├── crud.py      #データベース操作の関数を記述
├── database.py  #後述
├── dps.py       #後述
├── models.py    #テーブル定義
```

**database.py**
```python
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

import os

# Cloud SQLの接続情報を環境変数から取得
db_user = os.environ.get('DB_USER')
db_password = os.environ.get('DB_PASSWORD')
db_name = os.environ.get('DB_NAME')
cloud_sql_connection_name = os.environ.get('CLOUD_SQL_CONNECTION_NAME')

# データベースエンジンの作成
DATABASE_URL = f"mysql+pymysql://{db_user}:{db_password}@/{db_name}?unix_socket=/cloudsql/{cloud_sql_connection_name}"
engine = create_engine(DATABASE_URL, echo=True)

# データベースセッションの作成
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)

# データベースの構造などを定義する際に継承するクラスのようなもの
Base = declarative_base()
```

**dps.py**
```python
from . import database

def get_db():
    db = database.SessionLocal()
    try:
        yield db
    finally:
        db.close()
```
Pythonで「指定した値と同じ要素がタプルに含まれているか確認する」の動作を確認してみた

# 概要

Pythonで「指定した値と同じ要素がタプルに含まれているか確認する」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/python/tuple/index8.html

# 実装

以下のファイルを作成しました。
```sample.py
mytuple = ("A", "B", "C", "D", "E")
print("B" in mytuple)
print("D" in mytuple)
print("G" in mytuple)

mytuple = ("A", "B", "A", "A", "C")
print(mytuple.count("A"))
print(mytuple.count("B"))
print(mytuple.count("D"))

mytuple = ("A", "B", "A", "A", "C")
print(mytuple.index("A"))
print(mytuple.index("B"))
print(mytuple.index("C"))
#print(mytuple.index("D"))
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
True
True
False
3
1
0
0
1
4
```

# まとめ

何かの役に立てばと。
Rust 1.75.0リリースでasync fnをtraitで書けるように

# 概要

- Rust 1.75.0がリリースされた
- traitメソッドの戻り値を`impl Trait`にできるようになった
- それにより、`async fn`のメソッドもネイティブで書けるようになった

_引用：https://blog.rust-lang.org/2023/12/28/Rust-1.75.0.html_

# async fnをtraitで書けるようになった

このリリースの目玉機能は、`trait`のメソッドに戻り値が`impl Hoge`にできるようになったことです。

これまで長く待ち望まれた機能でしたが、実現するのにいくつか問題がありました。特に、`dyn Trait`の動的オブジェクトを使っている時のVtableにジェネリックが入ってしまうとどうすれば関数の呼ぶ場所を特定できるだろうか、これまでのRustだと不可能でした。

`fn method_a() -> impl Hoge`が`書けるようになって、さらに`async fn method_a() -> usize`のようなメソッドも書けるようになりました。

これは、`async fn foo() -> usize`は、構文糖であり、実際には`fn foo() -> impl Future<Output = usize>`で実際のステートエンジンがコンパイラによって生成されます。

なので、これがステーブルRustでできるようになったのはとても重要かつ重大な進歩であり、Async Rustにとって大きな勝利でもあります。Async Rustのコミュニティの長く掲げていた目標の一つでした。

# アップデートして使ってみよう

まず、アップデートは以下のコマンドでできます：

```
rustup update stable
```

それから任意のプロジェクトで書いてみましょう。

筆者の場合は、MySQLの`async fn`をずっと描きたかったのです。

```rust
trait Insert: Into<mysql_async::Params> + Send + Sync {
    async fn insert_stmt<T>(conn: &mut T) -> Result<mysql_async::Statement, mysql_async::Error>
    where
        T: mysql_async::prelude::Queryable,
        Self: Sized;

    async fn insert<T>(self, conn: &mut T) -> Result<u64, mysql_async::Error>
    where
        T: mysql_async::prelude::Queryable,
    {
        let stmt = Self::insert_stmt(&mut *conn).await?;

        conn.exec_drop(stmt, self).await?;

        let id = conn
            .exec_first("SELECT LAST_INSERT_ID();", ())
            .await?
            .unwrap();

        Ok(id)
    }

    async fn batch<T>(v: Vec<Self>, conn: &mut T) -> Result<(), mysql_async::Error>
    where
        T: mysql_async::prelude::Queryable,
        Self: Sized,
    {
        let stmt = Self::insert_stmt(&mut *conn).await?;

        conn.exec_batch(stmt, v.into_iter()).await
    }
}
```

これで`INSERT INTO ....`のステートメントだけ書けば、似たようなロジックを書かずにモデルがかけます！

```rust
pub struct List {
    pub list_id: u64,
    pub name: String,
    pub family_id: u64,
    pub items: Option<Vec<Item>>,
}

impl Into<Params> for List {
    fn into(self) -> Params {
        Params::Positional(vec![
            self.name.into(),
            self.family_id.into(),
            self.list_id.into(),
        ])
    }
}

impl Insert for List {
    async fn insert_stmt<T>(conn: &mut T) -> Result<mysql_async::Statement, mysql_async::Error>
    where
        T: mysql_async::prelude::Queryable,
        Self: Sized,
    {
        conn.prep("INSERT INTO lists (`name`, family_id, list_id) VALUES (?, ?, ?);")
            .await
    }
}
```

そうするとこのように使えます。

```rust
let mut conn: mysql_async::Conn = state.pool.get_conn().await.unwrap();
let list_id = list.insert(&mut conn).await.unwrap();
```

またもっと楽しいこともできます：
```rust
async fn insert_bulk_transaction<T>(conn: &mut Conn, v: Vec<T>) -> Result<(), mysql_async::Error>
where
    T: Insert,
{
    let mut t = conn.start_transaction(TxOpts::default()).await?;

    let stmt = match v.first() {
        Some(obj) => <T as Insert>::insert_stmt(&mut t).await?,
        None => return Ok(()),
    };

    t.exec_batch(stmt, v.into_iter()).await?;

    t.commit().await
}
```

# まとめ

以上、Rust 1.75.0の目玉商品`async trait fn`を紹介しましたが、皆さんも楽しんでお使いください。
日本語プログラミング言語Mindに欲しい機能

# mindに欲しい機能を議論したいと思います。
[mindの研究　その41-mind 良いところ、悪いところ](https://qiita.com/ohisama@github/items/1970e6c7967733008542#comment-58673685ec664f54e364)では、mindの弱点として
・jsonパーサが無い。
・正規表現エンジンが無い。
・ソケットが弱い。
・guiが無い。
・ActiveXが呼べない。
・データーベースが無い。
などが挙げられています。
guiは次期mind v9 でtk を使って実装予定と聞いています。
この他にもあると良い機能について優先度・実装方法などを検討し、mind作者の @killy さんに提案していきたいと思いますので、よろしくお願いします。
他の言語で作成されてソースが公開されているものは、それをmindに書き換えることも可能な場合もあると思いますのでお知らせください。
Mindをお使いでない方は
[Mind プログラミングマニュアル](https://www.scripts-lab.co.jp/mind/ver8/doc/index.html)　を参考にしてください。
[Mind ダウンロード　ページ](https://www.scripts-lab.co.jp/mind8download/download.html)　で無料でダウンロードできます。
[Mindサポート掲示板](https://www.scripts-lab.co.jp/support/public/html/mind.cgi?tframe+035+-s+F001)　に結果を集約できたらと思います。
読書感想　プログラマー脳

# 書籍名「プログラマー脳」
著者：Felienne Hermans
訳：水野貴明
監訳：水野いずみ

# 読もうと思った動機

ソードコードを読む能力を向上させたいから



# 印象に残った部分

## Ch1コーディング中の混乱の原因
１．知識不足
    原因：長期記憶不足（HDDにデータが無い）
　　対策：学習する
２．情報不足
    原因：短期記憶の問題（メモリに読み込まれていない）
　　対策：依存関係グラフを書く。CH4 
３．処理能力不足
    原因：処理能力の不足（CPU不足）
　　対策：状態遷移図を書く。CH4
例：台形の面積を計算する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/d9993f07-bc32-6e42-5ca7-15c523cc50c7.png)


## Ch3コードを速く読む方法
### コードを読むのが苦手な理由：
１．コードを書く練習はしていても、読む練習はしてないから
２．人間の短期記憶は貧弱のため
　　短期記憶はPCで例えるとRAM
### 根拠：ミラーの法則「普通の人が短期記憶に保持できるのは7(+-2)まで」

### 対処方法
短期記憶を克服するにはチャンク化を活用する
チャンク化：複数の情報を塊にすること

コードをチャンク化するための方法
１．コメントを書く。
コメントを起点としてチャンク化できる。

２．デザインパターンに当てはめる


### チャンク化の例
1192作ろう鎌倉幕府
クラ◯アンのCMの電話番号連呼するやつ


## プログラムの文法を習得する方法

分散学習、フラッシュカードを使って文法を習得する。

フラッシュカード学習をする頻度
ウォズニアックの間隔反復を参考

n回目の複数|何日後
---|----
１|翌日
2|７日後
3|16日後
4|35日後
5|62日後




https://oqilaqupace.com/learning/study-method/iterative-and-distributed-learning/






# 実践できること or 感想

## すぐに実践すること
### フラッシュカード学習法を試す
何度も本の中でフラッシュカード学習法の有用性を説いていたので実践します。
資格勉強に応用していこうと思います。
自分の場合だとPHP8初級試験とhtml5 プロフェッショナル認定試験を勉強します。
ankiに問題を作ってスキマ時間でコツコツ勉強します。



CH6以降が自分にとって難しかったです。モデルとかわからんです。


## いつか実践すること

### 本の演習問題をこなす

この本演習問題が多いのですが、やる気が起きなかったです。
いつかやります。
個人的な学習のメモ

## ノート
1. Udemyの教材でReactとGoを学んだ。
1. Reactでhooksを利用しているときにuseMemoのことをもう少し理解したほうが良いと感じて調べた。
1. コンポーネントをキャッシュ化しておくのに使う。（概ねそれまでの理解と合っていた）
1. 利用シーンとしてはよく再レンダリングするコンポーネントの子コンポーネント（再レンダリング不要）に使うらしい。

## キュー
useMemoってどういう場面で使うんだっけ？

## サマリー
React hooks の利用シーン（useMemo）
SwiftUI LazyVGrid利用時にViewのスペースを割り当てる優先順位を変更

SwiftUIの[LazyVGrid](https://developer.apple.com/documentation/swiftui/lazyvgrid)は子ビューに指定したViewをグリッド状に並べることができるViewです。
ただし遅延して表示するため、レイアウトを組む場合Viewのスペースを割り当てる優先順位を考慮する必要があります。
どう考慮すべきかを`HStack`の子ビューに`LazyVGrid`を指定する場合で解説します。

| | バージョン |
|:-----------|:------------:|
|Xcode|15.1|
|iOS|17.0|
|macOS|Sonoma 14.0|

# 作成物
`HStack`の子ビューに`LazyVGrid`(グリッド状に並べた絵文字)と`Button`を指定し、このようなViewを作成します。
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/b876b2b9-8d36-0429-91fc-49e18262e5bc.png">

# Viewのスペースを割り当てる優先順位を考慮しない場合
Viewのスペースを割り当てる優先順位を考慮せず、以下のように実装しビルドするとViewが中央に寄ってしまいます。
```swift:LazyVGridSample.swift
struct LazyVGridSample: View {
    var body: some View {
        HStack {
            LazyVGrid(columns: [GridItem(.adaptive(minimum: 20))]) {
                ForEach((0...24), id: \.self) {
                    let codepoint = $0 + 0x1f600
                    let emoji = String(Character(UnicodeScalar(codepoint)!))
                    Text("\(emoji)")
                }
            }
            Button(
                action: { },
                label: { Text("ボタン") }
            )
            .frame(width: 60)
        }
        .padding(16)
    }
}
```

<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/776b5fb9-ec3d-10ff-4b2a-614ae069dd80.png">

`LazyVGrid`は遅延して表示されるため、`Button`が先に表示されることが原因となります。

# Viewのスペースを割り当てる優先順位を考慮する場合
上記の問題を解決するために、[layoutPriority](https://developer.apple.com/documentation/swiftui/view/layoutpriority%28_:%29)を用いてViewのスペースを割り当てる優先順位を変更します。
`LazyVGrid`に`.layoutPriority(1)`を指定し、`Button`に`.layoutPriority(0)`を指定します。

```swift:LazyVGridSample.swift
struct LazyVGridSample: View {
    var body: some View {
        HStack {
            LazyVGrid(columns: [GridItem(.adaptive(minimum: 20))]) {
                ForEach((0...24), id: \.self) {
                    let codepoint = $0 + 0x1f600
                    let emoji = String(Character(UnicodeScalar(codepoint)!))
                    Text("\(emoji)")
                }
            }
            .layoutPriority(1)
            Button(
                action: { },
                label: { Text("ボタン") }
            )
            .frame(width: 60)
            .layoutPriority(0)
        }
        .padding(16)
    }
}
```

すると`LazyVGrid`を表示するスペースの優先順位が高くなるため、このように表示できます。

<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/b876b2b9-8d36-0429-91fc-49e18262e5bc.png">
Elixir用AtCoderの自動テストをLivebookで実現できるか検討


# やりたいこと

LivebookにAtCoderの回答を書いて、テストボタンを押すと、問題にある入力例を入力して実行して、結果が正しいか判定する。
提出ボタンを押すと、回答が提出される

コマンドラインでは、[この記事](https://qiita.com/GeekMasahiro/items/0970d7300f2bfcb28464)で紹介した方法でできてるんですが、Livebookでできたら、環境構築とかせず使えて面白そう。

## 要件
プログラムは変更せず、AtCoderに提出可能なものでテストを実行する。

## 必要な機能
- 入力例、出力例をAtCoderから取得 →なんとかなるだろう（未調査）
- stdioをfileにして実行　→課題
- 結果の比較　→問題ない ExUintで実装

# :stdioをfileにして実行する方法

コマンドラインで実行すれば何とでもできますが、Livebookで実現する方法が課題です。
次のような方法をとってみました。
- MyIOを作って、IOの代わりにMyIOを使う。
- MyIOは環境変数の設定で、deviceをstdioかファイル化を切り替える


# Livebookで作ってみた

入力をそのまま返すプログラムを作って、テストしてみました。
回答プログラムは、AtCoderのコードテストでも変更なしで動作しました。

```elixir:回答プログラム
defmodule Main do
  def input(), do: MyIO.read(:line) |> String.trim()

  def main() do
    s = input()
    MyIO.puts(s)
  end
end

defmodule MyIO do
  def read(_device \\ nil, option) do
    {file_in, _} = Application.get_env(:my_app, :file, {:stdio, :stdio})
    IO.read(file_in, option)
  end

  def puts(_device \\ nil, item) do
    {_, file_out} = Application.get_env(:my_app, :file, {:stdio, :stdio})
    IO.puts(file_out, item)
  end
end
```

```elixir:テストプログラム
ExUnit.start(autorun: false)

defmodule MyTest do
  use ExUnit.Case, async: true

  test "test case 1" do
    {:ok, file} = File.open("in_1.txt", [:write])
    IO.write(file, "aaa\n")
    File.close(file)
    {:ok, file_in} = File.open("in_1.txt", [:read])
    {:ok, file_out} = File.open("out_1.txt", [:write])
    Application.put_env(:my_app, :file, {file_in, file_out})

    Main.main()

    File.close(file_out)
    {:ok, file_out} = File.open("out_1.txt", [:read])

    assert IO.read(file_out, :line) == "aaa\n"
  end
end

ExUnit.run()
```

# 今後の課題

- MyIOを提出プログラムに追加しないといけない所がダサい。
- MyIOがread,putsだけしか実装されてないので限定的だが、多くの問題には対応できるので、実用性はなくはない。
- stdio自体をfileに置き換えれたら、任意のIO関数が使えて望ましいけど、不明。
- Moxなどモックを実現する方法でIOを置き換える方法はどうか？

いい方法のコメントも歓迎です
SpringBoot3でUsernamePasswordAuthenticationFilterを使うとセッションが落ちる

## はじめに
SpringBoot3.xにアップグレードするとログインできなくなるプロジェクトがありました。
本家のアップグレードのドキュメントを見ても特に変更漏れが無くハマった為、記載しておきます。
同一の症状が出ている人は参考にしてみてください。

## 環境

- SpringBoot 3.1.6
- Java 17
- spring-boot-starter-security
- spring-session-jdbc
- UsernamePasswordAuthenticationFilterクラスを使用して拡張

ログイン後DBにセッションは書きこまれていましたが、何故かログインすらできませんでした。

## 簡易修正方法
SecurityFilterChainにてHttpSecurityで設定できるrequireExplicitSaveにfalseを入れるだけです。
```java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
    http
    //...
    .securityContext(
        (securityContextCustomizer) -> {
            securityContextCustomizer.requireExplicitSave(false);
        })
    //...
}
```

falseはSpringBoot2の頃のデフォルトとのこと。
これでアップグレード以前と同じ状態になりログイン可能になります。

## 原因

どうやら認証まわりで仕様変更があったらしくデフォルトで使われるクラスが変更されたそうです。
具体的にはSecurityContextPersistenceFilterからSecurityContextHolderFilterに変更になったとのこと。
SecurityContextPersistenceFilterは現在非推奨となっておりソースを覗いても@Deprecatedがつけられています。
正しくはSecurityContextの明示的な保存をする必要性があるらしいです。

## 試しに明示的に書いてみる

UsernamePasswordAuthenticationFilterを継承したクラスに書いてみました。
attemptAuthenticationメソッドにてコンテキストを書きこんでます。
SecurityContextRepositoryはコンストラクタで作成してます。
ドキュメントに乗っているデフォルトの方法と同じにして親クラスに渡すことにしました。

```java
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private SecurityContextRepository securityContextRepositoryCustom;

    public CustomAuthenticationFilter(){
        this.securityContextRepositoryCustom =new DelegatingSecurityContextRepository(
                new RequestAttributeSecurityContextRepository(),
                new HttpSessionSecurityContextRepository());
        super.setSecurityContextRepository(securityContextRepositoryCustom);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
        //...
        SecurityContext securityContext = SecurityContextHolder.getContext();
        SecurityContextHolder.setContext(securityContext);
        securityContextRepositoryCustom.saveContext(securityContext, request, response);
        //...
        return this.getAuthenticationManager().authenticate(authRequest);
    }
    //...
}
```
一応セッションが落ちずに動きました。

## 備考
明示的な保存方法は断片的なソースのみでサンプルが見つかりませんでした。
HttpSecurityにて明示的に書き込むような方法が思いつかず、リクエスト単位で通るフィルタに記述したところ動きました。
明示的な保存方法についてもし正しい書き方を知っている方がいらっしゃいましたらご教授願います。
[Golang]Googleログインを実装してみる

Golangのシンプルさと強力な機能を組み合わせて、Googleログインを実装する方法を学びます。このガイドでは、コード例と実践的なアドバイスを通じて、認証プロセスの設計と実装のコツを掴んでいきます。初心者でも理解しやすいように、基本的な原則から始めます。

## Googleログインの仕組み

Googleに限らず、多くのシングルサインオンは以下のようになっています。

1. GoogleアカウントにログインするページにコールバックするURLを踏めてリダイレクトする
2. ログインする
3. codeのクエリーパラメータとともにコールバック用のページに飛ぶ
4. codeをClientIDとClientSecretを使ってアクセストークンを取得する
5. Userテーブルを必要に応じて作成
6. JWTを作成して必要な情報含めてフロントに返す


今回はGoogleログインができることさえ確認が出来れば良いの4までを実装する

## 必要なライブラリをインストール

```
go get golang.org/x/oauth2
go get golang.org/x/oauth2/google@v0.15.0
```

## GCPからcredentialを取得してコードに含める

ログインの認証に必要なのは以下の3つです。
初期化関数の引数に含めてください。

- ClientID
- ClientSecret
- RedirectURL

```golang
func NewGoogleOauthConfig(clientID string, clientSecret string, redirectUrl string) *oauth2.Config {
	conf := &oauth2.Config{
		RedirectURL:  redirectUrl,
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Scopes:       []string{"https://www.googleapis.com/auth/userinfo.email"},
		Endpoint:     google.Endpoint,
	}

	return conf

}

```

## GoogleアカウントにログインするページにコールバックするURLを作成する

下のコードでGoogleのログインページへのURLが生成されるので実際にログインをしてください

コールバックでエラーになっていると思いますがクエリーパラメーターにcodeがついてきているはずです。

```golang
func TestGoogleOauthConfig(t *testing.T) {
	googleOauthConfig := NewGoogleOauthConfig(clientID, clientSecret, redirectUrl)
	url := googleOauthConfig.AuthCodeURL("state", oauth2.AccessTypeOffline)
	fmt.Println(url)
}
```

## アクセストークンを取得する

アクセストークンはconfigのライブラリの関数のレシーバー関数で簡単に取得することができます。

```golang
func GetUserInfo(conf *oauth2.Config, token *oauth2.Token) (string, error) {
	client := conf.Client(oauth2.NoContext, token)
	response, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
	if err != nil {
		return "", err
	}

	userInfo := make(map[string]interface{})
	err = json.NewDecoder(response.Body).Decode(&userInfo)
	if err != nil {
		return "", err
	}
	fmt.Println(userInfo)
	userName := userInfo["email"].(string)

	return userName, nil
}

func Show(w http.ResponseWriter, r *http.Request) {
	code := r.URL.Query().Get("code")

	clientID := ""
	clientSecret := ""
	redirectUrl := ""
	googleOauthConfig := NewGoogleOauthConfig(clientID, clientSecret, redirectUrl)
	token, err := GetAccessToken(googleOauthConfig, code)
	if err != nil {
		fmt.Println(err)
	}
	username, err := GetUserInfo(googleOauthConfig, token)
	if err != nil {
		fmt.Println(err)
	}
　　 w.Write([]byte(username))
}

func main() {
	http.HandleFunc("/callback", Show)
	http.ListenAndServe(":3000", nil)
}


```



このコードを実行してから先ほとのログインの手順を実行して見てください。

これでブラウザでgmailのアドレス表示されます。

## 質問等があるかた

質問はTwitterで募集しております

https://twitter.com/YukiAsano3
WSL2にブラウザからアクセスする

お疲れ様です。秋並です。

今回は、ブラウザ上からWSL2にアクセスする手順について解説したいと思います。(jupyter labのようなイメージ)

正確には、下図のように
1. WSL2上でvisual studio code(vscode)のサーバーを立てる
2. WSL2上で立てたサーバーにブラウザからアクセスする

という流れになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/90bd3bce-a287-d921-b626-d6a9212af92d.png)

## 事前条件
WSL2+ubuntuがインストールされており、使用できる状態になっている。
参考サイト：[WSL2のインストールを分かりやすく解説【Windows10/11】](https://chigusa-web.com/blog/wsl2-win11/)
## 動作環境
- windows 11
- ubuntu 22.04

# CLI版のvscodeのダウンロード
最初に、以下サイトよりCLI版のvscodeをダウンロードしてください。
[https://code.visualstudio.com/Download](https://code.visualstudio.com/Download)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/90131814-4488-f4d0-959f-e915265b303a.png)<br>
次に、ダウンロードしたファイルを解凍すると、「code」という名前の実行ファイルが出力されるので、WSL2上の任意のディレクトリにコピーしてください。

:::note
WSL2上で
```
explorer.exe .
```
と入力すると、エクスプローラでWSL2上のディレクトリを開くことができるので、

今回のようなちょっとしたファイルを windows → WSL2 にコピーするときに便利です。

（もちろん、`cp`コマンドによりコピーすることもできます）
:::

# サーバーを立てる
先ほどコピーしてきた「code」があるディレクトリ上で、下記コマンドを実行することで、CLI版のvscodeを起動します。
```bash
./code serve-web --without-connection-token --accept-server-license-terms
```

この状態で、ブラウザから `localhost:8000` にアクセスすると、下図のようにvscodeの画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/56fdc6ed-4fb8-3df4-48cc-f8a9635074c5.png)

ここで、ターミナルに表示されているユーザー名を確認していただくと、WSL2で設定したユーザー名になっており、ブラウザからWSL2にアクセスできていることが分かると思います。

# サーバーを自動起動する
ここまでで、ブラウザからWSL2にアクセスすることは可能になりましたが、PCを起動するたびに上記のコマンドを実行するのは少々面倒なので、パソコン起動時に自動でサーバーが起動するようにしたいと思います。
<br>

1．最初に、windows上で「タスクスケジューラ」を起動してください。
起動が完了したら、「基本タスクの作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/842ef17b-1183-e1fb-6455-0be33bc2fd65.png)<br>
<br>

2．「タスクの名前」を設定します。名前はご自身が分かりやすい任意の名前でOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/7676ace8-f08c-8ea9-8c96-94d00b5ce8f0.png)<br>
<br>

3．「トリガー」を設定します。「ログオン時」を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/145fb860-dc43-ac3a-9f6b-701b484481a2.png)<br>
<br>

4．「操作」を設定します。「プログラムの開始」を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/261b45d2-a177-4010-5a7f-cb0294b4cc49.png)<br>
<br>

5．最後に、プログラムを下記のように設定します。
- 「プログラム/スクリプト」：wsl.exe
- 「引数の追加（オプション）：cd ＜「code」があるディレクトリまでのパス＞; ./code serve-web --without-connection-token --accept-server-license-terms
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/639f3594-06ad-3f56-730c-33ba2c8ea1ef.png)
:::note
＜codeがあるディレクトリまでのパス＞はご自身の環境に合わせて置きかえてください。
:::

上記でサーバーの自動起動の設定は完了です。

PCを再起動した際も、`localhost:8000`にアクセスできることを確認してみてください。

## オプション
上記の設定の場合、「ACアダプタに接続されているときのみ」タスクが実行されるので、常にタスクを実行したい場合は、設定を変更しておくとよいと思います。

（下図の「コンピュータをAC電源で使用している場合のみタスクを開始する」のチェックを外す）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/0f2fe45e-7ad0-48fb-f9d1-0d0ee8cccd72.png)

# さいごに

今回は、
- VScodeを介して、ブラウザからWSL2にアクセスする方法

について解説しました。

ブラウザからローカルのWSL2にアクセスできることにどれだけ需要があるかわかりませんが、この記事が少しでも皆さんのお役に立てれば幸いです。
GitHubの言語バーからJupyter Notebookを除外する

## 事象
`GitHub`において、アプリ開発で扱ったアルゴリズムの妥当性確認として、`Jupyter Notebook`に計算の可視化記録を残したいとき、ありますよね。
しかし、特に可視化した際画像の分のbyte数が大きいので、言語バーが`Jupyter Notebook`に占拠されてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/08bfffdd-c6c4-5da8-e2cf-80bf9f1e6747.png)

気にしない人は気にしないかもしれませんが、人によっては「この人もしかしてNotebookでアプリ作った気になったの？」と思われそうで嫌だと神経質になるかもしれません。

## 解決
そんなとき、 **レポジトリ直下に** 下記が書かれた`.gitattributes`という名前のファイルを置けば、`Jupyter Notebook`を無視できます。
```.gitattributes
# ignore jupyter notebooks in the language bar on github
**/*.ipynb linguist-vendored
```
参考: https://github.com/github-linguist/linguist/blob/master/docs/overrides.md

これで[見栄っ張りの王、見栄っ張りキング](https://qiita.com/uts1_6/items/11e348ead4bae71571b8)になれますね。
Dataverse の学習メモ「Microsoft Dataverse 内の環境」

https://learn.microsoft.com/ja-jp/training/modules/create-manage-environments/1-intro

1.手段
---
　環境は、Dataverse データベースのインスタンスを作成および管理するための手段。
　環境内の Dataverse データベースに関連付けられたユーザー アクセス、セキュリティ設定、およびストレージを管理する目的にも使用される。

2.許されること
---
　Power Apps を使用して構築したアプリケーションや、Power Automate を使用して作成したフローをその環境内にインストールすることが許可される。

3.作成数
---
　必要に応じて 1 つまたは複数作成できる。

4.どこに
---
　Microsoft Entra ID テナントの下に作成される。
　そのリソースにアクセスできるのは、テナント内のユーザーだけ。

5.紐づけ
---
　地理的な場所 (米国など) にバインドされる。
　環境内に Dataverse データベースを作成した場合、そのデータベースは、該当する地理的な場所にあるデータ センター内に作成される。
　その環境で作成したすべての項目 (接続、ゲートウェイ、Power Automate を使用しているフローなどを含む) も、その環境の場所にバインドされる。

6.所感
---
テナントがホールディングスで、環境がカンパニー。
Shell大好きなのでShellのリポジトリ作った。Pull Requestお願いします。

作業中に音楽を流したい時とかにShell Scriptを書くな〜〜と思ったので、SHellに特化したリポジトリを作りました。

https://github.com/SuperHotDogCat/SHELL_COMMANDS

今あるシェルスクリプトはこんな感じです。

・playMusicNtimes.sh: 同じ音楽をN回ループ再生したい時用です。

・bgm.sh: あるディレクトリにある音楽を全て再生したい時用です。

・startWork.sh: 仕事を始める時にとりあえず開くものです。macのみの対応かも, .bashrcなどに書き込むとterminalを開くだけで実行できます

・startReport.sh: レポートとかを始める時にとりあえず開くものです。macのみの対応かも, .bashrcなどに書き込むとterminalを開くだけで実行できます

・remind.sh: 何か忘れている予定がある気がする時に起動するものです。

# Pull Requestお願いします
みんなが使ってる便利なシェルコマンドを集めたいのでもしよければPull Requestしてください

### ルール
- bashかzshでお願いします
- 追加する際はREADME.mdに追加したシェルスクリプトの説明をお願いします。
- macosしか使えない場合はその旨を記入してください。
JavaScriptのURL操作

JavaScriptはよくWebブラウザやWebサーバーで使われるので、URLを操作することもあります。
URLの値を取得したり、操作したりする方法をメモします。
使用しているのURLは私の過去の投稿記事です。

```js
const url = new URL('https://qiita.com/yuta-10112022/items/81e7ac587aaa6afeb3e4');
console.log(url.href); // https://qiita.com/yuta-10112022/items/090d4f302f1edcefcf86
console.log(url.origin); // https://qiita.com
console.log(url.protocol); // https:
console.log(url.hostname); // qiita.com
```
urlのプロパティは読み書きすることができ、部分的に変更することができます。
```js
const url = new URL('https://example.com');
url.pathname = 'api/search';
url.search = 'p=test';
console.log(url.toString()); // https://example.com/api/search?p=test
```

#### 参考

https://www.amazon.co.jp/JavaScript-%E7%AC%AC7%E7%89%88-David-Flanagan/dp/4873119707
APIを雑に作る

## 暇なのでAPIを作ってみる
- 作るもの：ローランド判定API
- 環境
    - MacBook Pro
    - Poetry+pyenv仮想環境

## 手順
以下の手順に従ってプロジェクトフォルダを作成
https://qiita.com/takumayagi/items/be00d0ae7932befcc6e5

`main.py`にこんなことを書く
```python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "ローランド判定APIです"}

@app.post("/")
def sayHello(name: str):
    if name == "ローランド":
        return {"result": "俺"}
    else:
        return {"result": "俺以外"}

if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
```

API起動
```bash
$ uvicorn main:app --reload

INFO:     Will watch for changes in these directories: ['/path/to/dev/dir']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [91718] using StatReload
INFO:     Started server process [91720]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
```

ブラウザで`http://127.0.0.1:8000`にアクセスする(='/'にGETする)
```
{"message":"ローランド判定APIです"}
```

でけた。

`http://127.0.0.1:8000/docs`にアクセスするとこんな画面が出現

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1152756/163b2fc8-6142-aa55-e767-32a352e50cc1.png)

試しにローランドと入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1152756/91f2c527-ec2f-8d4e-e961-bb75053f3179.png)


こんな返答が返ってきた。いいぞ！

```
{
  "result": "俺"
}
```

ローランド以外を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1152756/1f32050e-b2e4-03b5-9291-aaa1436a6b8a.png)

```
{
  "result": "俺以外"
}
```

想定通り！
雑に作る、でした。
一度Runして誤ったOutputが出てしまうのをなんとか新しい結果に上書きしたい

一度Runして誤ったOutputが出てしまうのをなんとか新しい結果に上書きしたい
そんなときの解決方法。


# 問題
なぜかコードを書き直したのに誤った結果（グラフや出したい表など）がずっと永遠に出る。(この仕様はだれが幸せになるのだろうか？）

# 原因
KernelがRestartされないと永遠に記憶されたままRunしてしまい、せっかく苦労して書き直したコードがうまく結果として現れません。

# 対処法
Restart & Run Allしましょう。
下記画像はJupyterだけど、Google Colaboratoryにも似たようなものがあるはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334349/b5ceff36-1651-9a37-20f5-999e27b52118.png)
Python3エンジニア認定基礎試験 勉強してみた1

# 「**Python3エンジニア認定** **［基礎試験］**」 合格を目指します。

## 使用教材：
・Pythonチュートリアル第4版 --オライリー・ジャパン--
・徹底攻略Python3エンジニア認定基礎試験 問題集 --impress--

ひとまず、**Pythonチュートリアル第4版**を一通り読みました。
その上で早速**徹底攻略Python3エンジニア認定基礎試験** **問題集**を解いていきます。

第1章は、**Pythonの特徴**についての問題のようです。
結果は **9問中9問正解**！！

第2章は、**テキストと数の操作**についての問題です。
結果は、**9問中5問正解**。

間違えた4問について確認していきます。

## 見直し
###### 【文字列のスライス位置［負数での指定］】
負数で指定する文字列のスライスは、以下のように数えます。
```
 | a | b | c | d | e | f | g |
-7  -6  -5  -4  -3  -2  -1
```

###### 【フォーマット済み文字列(f文字列)】
文字列の中に式の値を入れられます。
式の後にフォーマット指定子のオプションを追加することで、
式の値に様々な書式を設定できます。
```
f"文字列{値:フォーマット指定子}"
```

###### 【フォーマット指定子】
主なフォーマット指定子は以下です。

<table>
  <thead>
    <tr>
      <th>フォーマット指定子</th> <th>意味</th>
    </tr>
  </thead>
  <tr>
    <td> b </td> <td>値を2進数で出力する</td>
  </tr>
  <tr>
    <td> d </td> <td>値を10進数で出力する</td>
  </tr>
  <tr>
    <td> x </td> <td>値を16進数で出力する</td>
  </tr>
  <tr>
    <td> f </td> <td>値を与えられた精度までの少数で出力する<br>（例：.5fで少数第5位で丸める）</br></td>
  </tr>
  <tr>
    <td> % </td> <td>値を100倍し、パーセント記号が付いた形式で出力する</td>
  </tr>
</table>


###### 【format()メソッド】
文字列の詳細なフォーマットを行うメソッドです。
```
#①フォーマットフィールドに引数のインデックスを記述する
"spam: {0}, ham: {1}, egg: {2}".format(x, y, z)
#②空のフォーマットフィールドを使う
"spam: {}, ham: {}, egg: {}".format(x, y, z)
#③フォーマットフィールドにキーワード引数の名前を記述する
"spam: {a}, ham: {b}, egg: {c}".format(a=x, b=y, c=z)
```

ただし、フォーマットフィールドには、format()メソッドに与えた引数の変数名は直接記述できないです。
以下の記述では**KeyError**が発生します！！
```
#KeyErrorになる記述例
"spam: {x}, ham: {y}, egg: {z}".format(x, y, z)
```
また、応用として以下のようにフォーマット指定子と組み合わせることもできる。
```
#整数3桁のゼロ埋めにする
"spam: {:03d}, ham: {:03d}, egg: {:03d}".format(1, 2, 3)
```
【出力結果】

```
spam: 001, ham: 002, egg: 003
```



次の記事
[Python3エンジニア認定基礎試験 勉強してみた2](https://qiita.com/SHIRYU_0515/private/84910ca285536e792ffe)