OmniAICreator/Qiita-1.07M huggingface dataset:
フリーランスエンジニアとなって経済的自由を得る方法（1.概要）

# フリーランスとなって経済的自由を得る！
<br>
こんばんは！間宮＠フリーランス6年目です。
<br>
<br>
フリーランスのインフラエンジニアとなってから資産構築に目覚め、今は経済的自由（FIRE)を目標に日夜奮闘しています。<br>現実的に目標達成が見えてきたのもあり、どうやって実現していくかを紹介したいと思います。

単価度外視でやりたい仕事をできる、週３だけ働く…などもっと自由に仕事を選べたら、きっと人生充実するとは思いませんか？

ここではフリーランスエンジニアの一番の強みである「今の手取りが増える」を最大限活かして、会社員と比較してのデメリットを乗り越え、さらに経済的自由を勝ち取る方法を書いていきたいと思います。

※長文になるため、数回に分けてアップしていきます。
書いている途中で目次や内容を修正する可能性がある点はご了承ください。

---
# 目次：

[1. 全体の考え方](#1-全体の考え方)
 　　　- [経済的自由とはなにか](#経済的自由とは何か)
 　　　- [資産形成戦略の概要](#資産形成戦略の概要)

---
※ここからは別記事になります。
2.[現状把握と生活防衛費](https://qiita.com/cryptomamiya/items/78f26b9f01ab591fbd84)
　　　1. 支出の把握
　　　2. 予算管理
　　　3. 生活防衛費（緊急予備資金）を意地でも貯める


3.[支出対策](https://qiita.com/cryptomamiya/items/8b70db41310ace42a094)
　　　1. 節約の基本方針
　　　2. 節約のアイデア
　　　3. その他の一般的な節約の話
　　　4. オススメしない節約方法

4.[節税対策](https://qiita.com/cryptomamiya/items/0badf9993987a694bcc6)

　　　1.節税の基本方針
　　　2.具体的な節税方法
　　　3.オススメしない節税方法
　　　4.限界まで節約してfireを目指す人向け

5.[資産形成(投資）](https://qiita.com/cryptomamiya/items/1b78354d47c17f47f990)
　　　1.貧すれば鈍する 一攫千金を狙わない
　　　2.例え一攫千金が実現できても破綻する
　　　3.スタンダードな投資から始めるのが一番
　　　4.ポジポジ病を避ける

6.[売上を増やす](https://qiita.com/cryptomamiya/items/ee4b42f74056896e49bc)
　　　1.直営業かエージェント経由か
　　　　- 直営業なら中抜きなし！いっぱい売上伸ばせるぞ！なのか？
　　　2.単価と仕事の難易度は一致するとは限らない
　　　3.安易な妥協は生涯年収を大幅に下げる
　　　4.一方で空白期間は案件獲得にマイナス
　　　5.空白期間を避けて希望単価で受注するには
　　　6.単価交渉は事前の準備が大事 エージェント任せにしない
　　　　-予算策定期間を考慮した交渉を
　　　　-単価交渉をスムーズに進めるには
　　　7.経済的自由に必要な単価はどれぐらいか

---
下記はおまけです

7.[フリーランスエンジニアのデメリットとそれを乗り越える方法](https://qiita.com/cryptomamiya/items/544202d13e73ad18e246)
　　- 1.年金が少ない
　　- 2.収入が不安定
　　- 3.高齢で仕事がなくなる
　　- 4.社会保険の不利
　　- 5.税金と健康保険面のデメリット
　　- 6.クレカと賃貸の審査
　　- 7.確定申告の手間

 ---

# 1. 全体の考え方

## 経済的自由とは何か
・最低限の用語解説（いろいろなFIRE)
|用語 |説明  |難易度  |自由度|
|---|---|---|---|
|コーストFIRE  |老後資金が貯め終わった状態|低|低|
|セミサイドFIRE|生活費の一定額を運用益でカバーする|中 |中  |
|サイドFIRE|最低限の生活費を運用益でカバーする|高 |高  |
|ファットFIRE|すべての生活費を運用益でカバーする|最大  |最大  |
<BR>
(※セミサイドFIREは間宮の造語)

この記事で目指す経済的自由は、「最低限の生活費を不労所得と少しの労働で賄える」という状況になります。不労所得だけで最低限の生活費を賄うサイドFIREに近いのですが、何もしないと資産の取り崩しが必要になります。といっても週3程度の労働で十分で、さらに老後になれば（月数万でも）年金があるのでその後はサイドFIREと同じ状況になります。
バリスタFIREという考えとも近いのですが、少し違うのでセミサイドFIREと私は呼んでいます。

いずれにせよ、フリーランスである強みを生かして極端な無理をせずに再現性高く資産を増やす方法を説明します。


## 資産形成戦略の概要
資産形成戦略の概要は下記のとおりです。
　　　1.現状の支出と適切な支出割合を把握する
　　　2.ストレスなく支出を抑える
　　　3.適切な節税対策を行う
　　　4.合理的な投資戦略により適切なリスクの下で資産を増やす
　　　5.自分の適切な「単価」を把握し、増やしていく

5．の段階まで来ると毎年驚く速度で資産が増えていくかと思います。
下記はおまけです

　　6.会社員と比較しての「デメリット」どう対処するか？
　　7.経済的自由が見えてきた人向け:将来の「自由」と今の「自由」とのバランスをどう考えるか

量はかなりありますが、私が実際に経験し、そして経済的自由が現実的に見えてきた方法になります。
フリーランスという選択を行われた、または選択を検討している皆様のライフプランの一助となることを願います。

それでは、各論に入っていきましょう！
Excel VBA 住所から郵便番号（数字のみ）を取り出す

とりあえず、コードを1行ずつ説明します。

A列のセルの中身を左から9個だけ取り出す
```vb
    ws.Cells(i, 2) = Left(ws.Cells(i, 1), 9)
```
取り出した9個の中から〒マークを消す
```vb
    ws.Cells(i, 2) = Replace(ws.Cells(i, 2), "〒", "")
```
最後に - を消す
```vb
    ws.Cells(i, 2) = Replace(ws.Cells(i, 2), "-", "")
```

全貌
```vb
Sub ExtractZipCode()

  Dim i As Long, LastRow As Long
  Dim ws As Worksheet
  
  Set ws = Sheets("Sheet5")
  LastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
  
  For i = 2 To LastRow
  
    ws.Cells(i, 2) = Left(ws.Cells(i, 1), 9)
    ws.Cells(i, 2) = Replace(ws.Cells(i, 2), "〒", "")
    ws.Cells(i, 2) = Replace(ws.Cells(i, 2), "-", "")
    
  Next i
    
End Sub
```
実行結果
![郵便番号を取り出す.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812230/42f51cef-e3b3-5cdc-3a7b-ddbf782db7b3.png)
住所がすべて配達局なのはたまたまです。
[Unity]ShaderGraphで影だけを描画する

仕事上の需要で、キャラクターやオブジェクトの影だけが落ちて、それ以外は描画されないようなshaderが必要になりインターネットの海で見つけたのが以下の記事。
https://qiita.com/kochiyukimoto/items/a687531ab94d21aa0801

DirectionalLightの影を落とすだけなら以下の画像のような効果がつくれます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411974/e04b525d-4f92-a1c5-2d66-4d741479d60f.png)

ただ、spotLightなどいわゆる追加ライトの影が落ちないようになっていため、現状のURPでの
対応を含めShaderGraph対応をしてみました。

# 結論
コードだけ知りたい方はここだけ見れば大丈夫です。
変更点は`GetAdditionalLight`で引数が１つ増えてます。
```hlsl  
//既存のコードはこれ
Light AddLight0 = GetAdditionalLight(i.worldPos);
//新規がこれ
Light AddLight0 = GetAdditionalLight(i, worldPos,1);
```  
これだけで追加ライトの対応は完了です。　とりあえず１にしておけば動くが、なぜ１でよいのかは調べ中。
追記(2024/09/01)  
最後の引数はshadowMaskというプロパティで、どうにも渡す値によらずこのプロパティがある方でのみライトの影減衰率を渡しており、これが影響している模様。

# ShaderGraph対応
カスタムノード化したコードがこちら。
```hlsl  
#ifndef YOTHUBALAB_RECEIVESHAODW_INCLUDED
#define YOTHUBALAB_RECEIVESHADOW_INCLUDED


#ifndef SHADERGRAPH_PREVIEW
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#endif
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT

void ReceiveShadow_half(float shadowAlpha,float3 worldPos, out half shadowAttenuation)
{
    #ifdef SHADERGRAPH_PREVIEW
    shadowAttenuation = 1.0;
    
    #else
    half4 shadowCoord = TransformWorldToShadowCoord(worldPos);
    Light mainLight = GetMainLight(shadowCoord);
    half shadow = mainLight.shadowAttenuation;
    int pixelLightCount = GetAdditionalLightsCount();
    for(int i = 0; i < pixelLightCount; i++)
    {
        Light AddLight0 = GetAdditionalLight(i, worldPos,1);
        half shadow0 = AddLight0.shadowAttenuation;
        shadow *= shadow0;
    }
    
    
    shadowAttenuation = shadow * shadowAlpha;
    #endif
   
}


#endif

```

カスタムノード自体の詳細は省きますが、`ifdef SHADERGRAPH_PREVIEW`
で分岐している箇所だけ説明するとShaderGraphのエディタ上で表示されるpreviewの描画でライト周りの関数にアクセスできないため、分岐で処理を分けています。
参考 https://blog.unity.com/ja/engine-platform/custom-lighting-in-shader-graph-expanding-your-graphs-in-2019

# 使用例
CustomNode化したコードをさらにサブグラフ化してしようしております。(GetShadow)  
サブグラフの出力であるShadowAttenuationは影部分で0,そうでない部分で１になるような数値ですので、
`OneMinus`してあげることで、影部分では１、そうでない部分では０となるようにします。
それをアルファに入力してあげることで、影部分以外を描画しないようなMaterialを作成できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411974/cafd307d-607d-0d46-1206-4981efae22ce.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411974/5640004d-79d3-c808-c155-c73db3330b13.png)
Windows on Armのx86/x86_64エミュレーションに関する技術資料集

# Windows on Armのx86/x86_64エミュレーション
x86/x86_64とArmでは命令セットアーキテクチャが異なるため、ArmアーキテクチャのCPUであるApple SiliconやQualcommのSnapdragonではx86/x86_64バイナリをそのまま動作させることはできません。Windows on Armでは様々な技術を用いてArm上でx86/x86_64をエミュレーションすることでユーザーモードのバイナリを実行できるようにしています。

この仕組みに関する技術資料へのリンクをまとめました。

## Windows on Armでのx86/x86_64エミュレーション
- [Appearances are deceiving: Novel offensive techniques in Windows 10/11](https://www.ffri.jp/assets/files/research/research_papers/Koh_Nakagawa_Appearances_are_deceiving_Japanese.pdf)
株式会社ＦＦＲＩセキュリティのKoh Nakagawa氏によるArm版Windowsでのx86/x86_64互換技術への攻撃方法のスライドです。主題はセキュリティですが、Arm版Windowsのx86/x86_64互換技術に関して日本語で説明している資料としては一番詳しいと思います。
- [ARM64 Boot Camp: The Windows on ARM Tutorials](http://www.emulators.com/docs/nx44_intro_to_woa.htm#abc)
Windows on ArmのWOW64のx86エミュレータxtajitの開発者でありx86_64互換に使われるARM64ECとARM64Xの仕様の設計者である[Darek Mihocka氏](http://www.emulators.com/DarekMihockaResume2022.pdf)によるWindows on Armに関する詳細な解説です。特に[ARM64EC](http://www.emulators.com/docs/abc_arm64ec_explained.htm)や[x86/x64 Emulation](http://www.emulators.com/docs/abc_exit_xta.htm)について機械語レベルでの非常に詳しい説明がされています。
- [Arm でのエミュレーションのしくみ](https://learn.microsoft.com/ja-jp/windows/arm/apps-on-arm-x86-emulation)
- [Arm64EC の概要](https://learn.microsoft.com/ja-jp/windows/arm/arm64ec)
- [Arm64EC ABIについて](https://learn.microsoft.com/ja-jp/windows/arm/arm64ec-abi)
Windows on Armでのエミュレーションの概要と、x86_64互換に使われるARM64ECについての概要と実際のApplication Binary Interface(ABI)に関するMicrosoftの解説です。

## メモリオーダリング
Armとx86/x86_64では[メモリーオーダリング](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%AA%E3%83%BC%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0)が異なります。なんらかの対策がないとArmでx86/x86_64のマルチスレッドやマルチプロセスのアプリケーションをエミュレーションするのは困難です。メモリオーダリングはややこしいので、資料のリンクを貼ります。

- [The Qualcomm Snapdragon X Architecture Deep Dive: Getting To Know Oryon and Adreno X1](https://www.anandtech.com/show/21445/qualcomm-snapdragon-x-architecture-deep-dive/2)
A Note on x86 Emulation以下にQualcommのSnapdragon X EliteのCPUコアであるOryonでのx86/x86_64エミュレーションに関する解説があり、[Apple Silicon同様](https://yamasa.hatenablog.jp/entry/2020/12/07/041649/)のx86_64との互換モードがあると推測しています。
- [プログラマーのためのCPU 入門 CPU は如何にしてソフトウェアを高速に実行するか](https://www.amazon.co.jp/dp/4908686165/)
CPUの高速化の仕組みの関する書籍で、第11章でメモリーオーダリングを取り扱っています。日本語で書かれた文書では一番わかりやすくメモリーオーダリングについて説明していると思います。
- [A Primer on Memory Consistency and Cache Coherence](https://course.ece.cmu.edu/~ece847c/S15/lib/exe/fetch.php?media=part2_2_sorin12.pdf)
Daniel Sorin氏Mark Hill氏David Wood氏によるメモリーオーダリングを含めたメモリの一貫性とキャッシュに関する書籍です。非常に詳細な説明がされています。

## WineでのARM64EC
- [WineのWikiのARM64EC-Toolchain](https://gitlab.winehq.org/wine/wine/-/wikis/ARM64EC-Toolchain)
LinuxやmacOS等でWindowsアプリケーションを動かせるようにする互換レイヤーである[Wine](https://www.winehq.org/)でのARM64EC対応に関する解説です(2025/2/20追加)。
jest.clearAllMocks()の記述は本当に必要か

## 初めに
元医療職 → WEB制作者がReact開発で詰まった箇所を日々発信しています！
現在はJISOUというコミュニティに所属してReact開発を学習中。

今回はReact・Typescriptで作成したアプリのテストで、`Unable to find an element by: [data-testid="register-modal"]`というエラーが出ました。
これを解決するためにchatGPTに質問をしていたのですが、jest.clearAllMocks()を使用する解決方法を示されました。

## jest.clearAllMocks()とは？
jest.clearAllMocks()とは、Jestのモック関数の状態をクリアするためのメソッドです。
例えば以下のように同一ファイル内で、テストが2つあった場合に

```typescript
import { fetchData } from './dataFetcher'; // モックする関数
import { processData } from './dataProcessor';

jest.mock('./dataFetcher');

describe('processData', () => {
  beforeEach(() => {
    jest.clearAllMocks(); // 各テストの前にモック関数をクリアする
  });

  test('should process data correctly', async () => {
    fetchData.mockResolvedValue({ data: 'sample data' });
    const result = await processData();
    expect(result).toBe('processed data');
    expect(fetchData).toHaveBeenCalledTimes(1);
  });

  test('should handle errors correctly', async () => {
    fetchData.mockRejectedValue(new Error('Fetch error'));
    await expect(processData()).rejects.toThrow('Fetch error');
    expect(fetchData).toHaveBeenCalledTimes(1);
  });
});
```

このファイル内ではテストが2つ存在しますが、
```typescript
beforeEach(() => {
 jest.clearAllMocks();
});
```
こちらの記述がないと、一つ目のモックのキャッシュが2つ目のテスト結果に影響を与える可能性があります。

## 今回の問題点
今回は同一ファイル内ではなく、異なるファイル内でモックが干渉している？ようでした。
ですがモックは基本的には異なるファイル内で、干渉することはないので`jest.clearAllMocks()`を使用する必要はありません。
ですが稀にモックのキャッシュが残ることがあるらしく、その場合には使用しても良い感じです。

## 終わりに
chatGPTにjest.clearAllMocks();について聞くと、他のモックが干渉しないように保険の意味合いで入れるのはいいと言っていました。
ですが他のファイルとの干渉を防ぐために使用する方法は、検索しても1つも引っかかりませんでした。
同一ファイル内で複数のテストを実施する際には有効な手段ですが、他のファイルとの干渉を防ぐという目的では使わないでおこうと思いました。
FileMakerのオブジェクトをS3にアップロードする

以前の[FileMakerからMySQLへのMigration](https://qiita.com/mackey1966/items/b22b6c3e2485363f43ab)の続きになる（もう2年も経つのか）。オブジェクトの移行例としてBase64への変換方法を記載した。

実際この方法でMySQLのlongtextに取り込んでみたが、既存のオブジェクトとBase64分で容量が2.5倍くらいになってしまう。FileMakerのデータの9割近くをオブジェクトが占めており、ただでさえサーバーのディスクを圧迫してプログレッシブバックアップもままらなくなっている状況でこれを採用するのは厳しい。MySQL側もDB内にオブジェクトデータを持つと肥大化し後々データの取り回しに困るだろう。

そこで、オブジェクトは外部に保存してMySQLにはリンクだけ持たせることにした。保存先はAWS S3を採用。セキュアに保つためにはいくつか方法があるが、取り敢えずMySQLにはファイル名だけ持って都度S3の署名付きURLを発行することにした（S3の署名付きURLについてはネットにいっぱい情報があるのでそちらを参考にしてください）。

手順は以下（Mac用）。
1. FileMakerからオブジェクトをエクスポート（出力するファイル名はGetContainerAttribute ( image ; "filename" ) などで取得）
2. シェルスクリプトなどでエクスポートしたファイルをS3にアップロード 

cronで1のFileMakerスクリプトと2のシェルスクリプトを5分毎とかに実行する

cronで呼び出すスクリプト
```csv_export.sh
#!/bin/sh
date
open 'fmp://<アカウント名>:<パスワード>@<FileMaker ServerホストのIPアドレス>/<FileMakerファイル名>.fmp12?script=Export updated data since last run for MySQL'
```
FileMakerスクリプトから呼び出すスクリプト
```csv_upload.sh
#!/bin/bash
 date
 cd /Users/<ユーザ名>/Documents/<一時CSV保存先のフォルダ名>/
 file1=*.csv
 sftp -i /Users/iwaninc/.ssh/dbserver.cer -oPort="<sftpポート番号>" <DBサーバのユーザ名>@<DBサーバのIPアドレス> << END
 cd temp/csv/
 mput $file1
 quit
 END
```
cronで呼び出すスクリプト
```upload_objects_to_s3.sh
#!/bin/bash

# cronで実行に必要
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
export PATH

# ログファイルのパス
LOG_FILE="/Users/<ユーザ名>/Documents/tmp/upload_script.log"

echo "$(date) Start..." >> "$LOG_FILE"

# アップロード先のS3バケット名
S3_BUCKET="<S3バケット名>"

# アップロード先のS3オブジェクトプレフィックス 
S3_PREFIX="<S3オブジェクトプレフィックス>"

# アップロードするファイルのあるローカルディレクトリ
TMP_DIRECTORY="/Users/<ユーザ名>/Documents/<一時画像保存先のフォルダ名>"

# オブジェクトファイルをアップロード
find "$TMP_DIRECTORY" -type f -print0 | while IFS= read -r -d $'\0' file; do
   if aws s3 cp "$file" "s3://$S3_BUCKET/$S3_PREFIX/$(basename "$file")"; then
       echo "$(date) Uploaded: $file" >> "$LOG_FILE"
       rm "$file"
   else
       echo "$(date) Upload failed: $file" >> "$LOG_FILE"
   fi
done

echo "$(date) Upload and deletion completed." >> "$LOG_FILE"
```
以上だが、FileMakerのオブジェクトフィールドは外部保存にしており、最初サーバーの外部保存ファイルをS3にアップしていた。

しかし、それだとFileMakerで取得するファイル名と外部保存されているファイルの名前が一致しないもの（拡張子の大文字が小文字になってたりheicやjpegがjpgになってたり）が出てきて問題だったのでオブジェクトフィールドをエクスポートする方法に変更した。エクスポートしたファイルの容量が問題になりそうだが上記をcronで5分毎とかに実行しているのでほとんど問題にならない。

ニーズがあるかどうかわからないがやったことの記録として上げときます。
Kaggle NotebookのコードをGoogle Colaboratryでそのまま使う

# Kaggle NotebookのコードをGoogle Colaboratryでそのまま使う方法
KaggleのLeashBELKAコンペに取り組んでいたのですが、Kaggle NotebookのGPUリソースだけでは立ち行かなくなったのでColabに課金しました。自分用に使い方メモを残していきます。
## 1.Colabで使いたいコードをKaggle Notebook上で開く

## 2.左上「File」タブの「Open in Colab」を押す
![スクリーンショット 2024-06-20 19.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/05bdfad2-46b9-9fb1-4cb3-e0fa38db4079.png)

押すと自動的にGoogle colabのNotebookが起動します。
![スクリーンショット 2024-06-20 19.47.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/9b7508ee-8b00-85fc-94ce-9dad1b7c1271.png)

## 3.最初のセルを実行
Kaggle Notebook上でインポートしていたデータ類はColab上の”kaggle”というディレクトリ内に引き継がれる。

## 終わりに
他にもtipsご存知でしたら教えてください、、、
markdown AIでサイト公開するまで

## はじめに

https://qiita.com/official-events/142fdd0d69ff6bb2d547

ちょうど生成AIをいろいろ試していることもあり、こちらのバナーを見て、面白そう!と思って参加することにしました。

## AIの搭載はこれから

markdownAIは下記から、Googleアカウントさえあれば無料で利用することができます。
markdownAIという名前ですが、**AI機能はまだなく、今のところただmarkdownで書いてそのままWebサイトとして公開できる**というアプリの模様。

https://mdown.ai/

機能はシンプルですが、Googleアカウントさえあればすぐに公開できるという点では、気軽に文書を公開したい際には便利そうです。
AIの搭載によりどのように使い方が変わってくるのか期待したいところです。


## Webサイトの公開までやってみた

chatGPTに適当に文章を書かせて、ブログっぽいタイトルにしてから貼り付けます。
UIはシンプルゆえに少し直感的にわかりづらいところがあります。
[View]と[Markdown]が切り替えられるようになっていますが、Qiitaのように横にプレビューが出てくれたほうが便利ですね。

![スクリーンショット 2024-06-20 19.31.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506559/5a55ba41-249a-3f44-a456-1e4133ee3ba3.png)

View画面で[Save]してから[URL]を押すと、公開するかどうか聞かれます。[Publish]を押すとサイト公開され、URLがコピーできます。
![スクリーンショット 2024-06-20 19.13.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506559/af326bd4-9840-453b-6732-a7119237f8c3.png)

できたサイトがこちら。

https://storage.googleapis.com/topdowncom/content/7U7V8S2ZGHctiLXMthU8Yy8L7Z83/dbd99a28-7042-43ae-9bcd-8a1cb87c2bb3/index.html

ちゃんと公開されています!
![スクリーンショット 2024-06-20 19.15.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506559/eb27a0ae-b449-91b9-2b63-6c18a94e42d8.png)

文章さえ準備できていれば、登録からサイト公開まで、5分もかからずにできてしまいました🎉

## サイトの設定

プロフィールアイコンから、設定画面に遷移できます。
Site Settingsでサイトのタイトルや画像を設定しておきましょう。
画像ファビコンになるようです。BingAIに出してもらったものをトリミングしました。
ついでにSaveTypeをAutoにしておきましょう。
![スクリーンショット 2024-06-20 19.26.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506559/7f197c12-2090-4ff5-514f-685382b48cd7.png)

## 感想

β版ということで、UXがいまいちだったり、AIが使えないというところはあるので、今後どう変わっていくか楽しみです。
GithubのWebページや、Notionを使うことでマークダウンで記載した文章を公開することもできますが、普段から使っている人でなければハードルはあるかと思います。それに比べると、markdown AIの手軽さはかなり便利だなと思いました。
AIが搭載されたら、markdownに慣れていない人でもテキストを打ち込むだけで自動でいい感じに整えてくれるようになるのでしょうか?🚀
GitHub Actions学んでみた③

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:

**「いいね」か「ブックマーク」**
を頂けると僕のモチベーションアップになります！:thumbsup:
少しでも気に入っていただけたらよろしくお願いいたします！:thumbsup:


# 今回の目的
自分の作ったコンポーネントを確認したり検証するための技術を身に付けたい！
公式のクイックスタートを参考に進めていきます。
項目ごとに補足のみ書いて進めています。わかりづらいところの理解の手助けになれば幸いです！

# 主に参考にさせていただいた記事

https://docs.github.com/ja/actions/quickstart

# GitHub Actions の重要な機能
環境変数、カスタマイズされたスクリプトなどを含む GitHub Actions ワークフローを作成する方法

## ワークフローで変数を使用する
下記の場合、envが変数です。
```yml
jobs:
  example-job:
    runs-on: ubuntu-latest
    steps:
      - name: Connect to PostgreSQL
        run: node client.js
        env:
          POSTGRES_HOST: postgres
          POSTGRES_PORT: 5432
```

## ワークフローにスクリプトを追加する
working-directoryは、runコマンドを実行する場所を指しています。
```yml
jobs:
  example-job:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./scripts
    steps:
      - name: Check out the repository to the runner
        uses: actions/checkout@v4  
      - name: Run a script
        run: ./my-script.sh
      - name: Run another script
        run: ./my-other-script.sh
```

## ジョブ間でデータを共有する
別のジョブで共有できるデータを作成するrunコマンドです。
```yml
      - name: Upload output file
        uses: actions/upload-artifact@v4
        with:
          name: output-log-file
          path: output.log
```
ダウンロード
```yml
      - name: Download a single artifact
        uses: actions/download-artifact@v4
        with:
          name: output-log-file
```

# 次
https://qiita.com/mr_noppo/items/6435a78e5a12be205cc3
Excel VBA Like演算子と条件分岐

## 特定の文字列を含むセルを指定するためLikeとIfを組み合わせる

A列の住所に「都島区」が含まれていたら、B列に「都島区」を入力する

条件設定
```vb
If ws.Cells(i, 1) Like "*都島区*" Then
    'A列に「都島区」が含まれていたら
```

プロシージャ
```vb
Sub HowToUseLike()

  Dim i As Long, LastRow As Long
  Dim ws As Worksheet
  Set ws = Sheets("Sheet5")
  LastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
  
  For i = 2 To LastRow
  
    If ws.Cells(i, 1) Like "*都島区*" Then
       ws.Cells(i, 2) = "都島区"
    End If
    
  Next i
  
End Sub
```

実行結果
![Like演算子.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812230/ae07fba9-4487-3430-8634-97c84b08b1a3.png)

参考ページ インストラクターのネタ帳
https://www.relief.jp/docs/excel-vba-if-like-instr.html
もうこれで終わりにしよう！wsl２でのGPU再環境構築(ubuntuの削除から再インストール、CUDA, Pytorch, wsl2)【新規環境/既存環境対応】

## はじめに
こちらは基本的に公式サイト[CUDA on WSL](https://docs.nvidia.com/cuda/wsl-user-guide/index.html#getting-started-with-cuda-on-wsl-2)を参照して作成した手順になる。
作成する環境は以下の[pytorch公式サイト](https://pytorch.org/blog/deprecation-cuda-python-support])の互換性マトリックスpytorch2.0に従う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484524/856e29c0-22d0-f1bf-6459-565c323e3aca.png)


## 作成する環境
wsl2：ubuntu 20.04
python：3.8.10
CUDA Toolkit 11.7
pytorch：2.0
## 既存環境

Windows11
GPU：NVIDIA GeForce RTX 3080 Ti
## 手順

1. ubuntuのインストール（＋アンインストール）
2. pytorchのインストール
3. CUDA toolkitのインストール

## 1. ubuntuのインストール（＋アンインストール）
初めてインストールする方は "#インストール" から始める。
もし、環境がぐちゃぐちゃになったり、上手くいかない場合はアンインストールをどうぞ！
```powershell
# PowerShell
# 削除
wsl --unregister Ubuntu-20.04

# インストール
wsl --install -d Ubuntu-20.04

```

## 2. pytorchのインストール

まずはアップデート

```powershell

# ubuntu
$ sudo apt update & sudo apt upgrade

$ sudo apt upgrade python3

# pipインストール
$ sudo apt install python3-pip
```
pytorchのインストールは公式サイト[Previous Pytorch Versions](https://pytorch.org/get-started/previous-versions/)のインストール手順になる。


```powershell
# pytorch install
$ sudo pip install torch==2.0.0 torchvision==0.15.1 torchaudio==2.0.1
```
以下のように出力されればインストール完了
```powershell
$ python3 -c "import torch; print(torch.__version__, torch.cuda.is_available())"
# 2.0.1+cu117 true
```

## 3. CUDA toolkitのインストール
Nvidia driverはwindows11の方にインストールしてある前提で進める。まだの方は[こちらから(latest NVIDIA Windows GPU Driver)](https://www.nvidia.com/Download/index.aspx?lang=en-us)

CUDA toolkitのインストールは公式サイト[CUDA toolkit 11.7(CUDA Toolkit 11.7 Downloads)](https://developer.nvidia.com/cuda-11-7-0-download-archive?target_os=Linux&target_arch=x86_64&Distribution=WSL-Ubuntu&target_version=2.0&target_type=deb_local)のインストール手順になる。



```powershell
# CUDA Toolkit 11.7インストール
$ wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
$ sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
$ wget https://developer.download.nvidia.com/compute/cuda/11.7.0/local_installers/cuda-repo-wsl-ubuntu-11-7-local_11.7.0-1_amd64.deb
$ sudo dpkg -i cuda-repo-wsl-ubuntu-11-7-local_11.7.0-1_amd64.deb
$ sudo cp /var/cuda-repo-wsl-ubuntu-11-7-local/cuda-*-keyring.gpg /usr/share/keyrings/
$ sudo apt-get update
$ sudo apt-get -y install cuda

# path設定
$ export PATH=/usr/local/cuda-11.7/bin${PATH:+:${PATH}}
$ export LD_LIBRARY_PATH=/usr/local/cuda-11.7/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
$ source ~/.bashrc
```

最後に確認作業
```
# CUDA toolkit確認（以下のような出力があればOK)
$ nvcc -V
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484524/68971a84-2e51-8598-2c1f-86def7ccd751.png)

## おわりに
何回かつまづいたGPUの環境構築でしたので書き留めてみました。少しでも皆さんのためになれたらと思います。最後まで読んでいただき、ありがとうございました。
C#で環境変数を使ってみよう ~Unityでも応用可能~

# 環境変数てなんのために使うの？

1. キーがコミットされるリスクを減らせる
2. 環境ごとに設定を変えられる

::: note warn
環境変数を設定してもクライアントに配布する場合、配布先にはキーが残ります。
メモリを解析されることによってキーが漏洩する可能性があるので、サーバーを用意してそこに委譲するのが安全です。
:::

# 実際に使ってみよう

1. キーを取得するコードを書く
```C#
using System;

public class SampleKey
{
    private string key =　Environment.GetEnvironmentVariable("SOME_KEY");
}
```

2. 環境変数を設定する

Windowから**システム環境変数**の編集を開きます。
![Env_search.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/4e45388a-432e-fca2-06fe-a47390820f22.png)

右下の環境変数(N)...をクリックします。
![Env_system.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/9282412a-ee08-3431-d672-fc36ba0b2aa4.png)

〇〇ユーザー環境変数の方の 新規(N) をクリックします。
![Env_value_deleted.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/a3c09f8d-bf5e-93e4-4970-44c5fb692b2a.png)

するとダイアログが開くので変数名に SOME_KEY 変数値に任意の値を入力します。今回は hoge としました。
SOME_KEYはあなたの好きな名前で大丈夫です。その際は関数の引数も変えてください。
```GetEnvironmentVariable(ここに変数名);```

3. **再起動をする**

::: note alert
自分の環境では再起動をしないと変数 key はnullになりました。
:::

# 動作確認をしてみよう

今回はUnityで動作確認をしていますが、C#であればどの環境でも使えます。

うまくSOME_KEY の値が取得できているので成功ですね！
![Env_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288957/f7b2d144-4b92-cbd2-a60a-5d320374b1ed.png)
MySQLで絵文字を条件に検索した時のめも

タイトルそのままなのですが、動作確認用のデータとして絵文字が含まれるレコードを探す必要があり、その時の対応内容を記しておきます。

MySQLのバージョンは8.0.28です。

### 前提
自分の環境は以下の状態です。
* 絵文字が登録可能なテーブル(`DEFAULT CHARSET=utf8mb4`)は既に存在している
* DB自体の`DEFAULT CHARSET`は`utf8mb4`ではない

`utf8mb4`とは何ぞや？とか`collations`って何さ！という方は以下の記事をご参照ください。
* [utf8とutf8mb4の違い【MySQL】](https://penpen-dev.com/blog/mysql-utf8-utf8mb4/)
* [【MySQL】照合順序とは？](https://qiita.com/kazu56/items/6af85ffcf8d3954455ad)

　
### 先に結論
mysqlコマンドで接続する時に`--default-character-set=utf8mb4`を追加してやればOK。
```
mysql -u username -h hostname --default-character-set=utf8mb4
```

普通に検索できました。
```
MySQL [db]> select * from bbs_threads where detail like '%🍣%'\G
************** 1. row **************
        id: 2
     title: 🍣🍣🍣🍣🍣
    detail: 🍣🍣🍣🍣🍣
created_at: 2024-06-17 03:35:21
updated_at: 2024-06-17 03:37:26
1 row in set (0.00 sec)
```


### いつも通りに接続するとどうなるか
`collations`が混在していると怒られました。
```
$ mysql -u username -h hostname
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 337138
Server version: 8.0.28 Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [db]> select * from bbs_threads where detail like '%🍣%'\G
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation 'like'
```

「Illegal mix of collations」で検索したところ、WHERE句に`COLLATE`を指定すればエラー回避できるという記事を見たので試してみましたが、自分の環境ではうまくいかなかったです。
```
MySQL [db]> select * from bbs_threads where detail like '%🍣%' COLLATE utf8mb4_general_ci;
ERROR 1253 (42000): COLLATION 'utf8mb4_general_ci' is not valid for CHARACTER SET 'utf8mb3'
```
　
おまけ。
文字コード指定なしの接続だと、id指定で検索したらデータ取得はできたのですが、絵文字部分は正しく表示されませんでした。
```
MySQL [db]> select * from bbs_threads where id=2\G
************** 1. row **************
        id: 2
     title: ?????
    detail: ?????
created_at: 2024-06-17 03:35:21
updated_at: 2024-06-17 03:37:26
1 row in set (0.00 sec)
```

文字コードまわりはちゃんと理解したいけど追いついていないところです。。
R での解析に使用したパッケージ一覧を出力する

## R での解析に使用したパッケージを記録しておくべき

Rが信頼性の高いソフトウェアであることは間違いありません、
しかし、公式リポジトリに登録されていて実績のあるパッケージであったとしても、バグが存在する可能性があります。
利用しているパッケージにバグが見つかった場合に備えて、使用したパッケージのバージョンを記録しておくことは重要です。

論文の査読者から要求される場合もあります。

### バージョンを出力するコード

セッションで利用したパッケージのバージョン一覧を表示するコードです。
一連の解析の最後に実行してください。

R markdown を利用しているなら、最後に書き足しておくとよいと思います。

```R:R
cat("Analysis is conducted using", R.version.string, "\n")

info <- sessionInfo()
packages <- c(info$otherPkgs, info$loadedOnly)
pkg_versions <- sapply(packages, function(pkg) paste(pkg$Package, pkg$Version))

cat("The script uses the following packages and versions:\n")
cat(pkg_versions, sep = "\n")
```

### コードの説明

- `R.version.string` は、現在のRバージョンを文字列で表したものです
- `sessionInfo()` 関数を使って、現在のRセッションに関する情報を取得します
- `info$otherPkgs` と `info$loadedOnly` を結合して、ロードされているパッケージのリストを作成します
- `sapply()` 関数を使って、各パッケージの名前とバージョンを文字列で結合します

## 出力例

このスクリプトを実行すると、以下のような出力が得られます。
これは、生存期間に対する多変量解析 (Cox比例ハザード回帰) の例です。

```
Analysis is conducted using R version 4.4.0 (2024-04-24) 
The script uses the following packages and versions:
compiler 4.4.0
Matrix 1.6-5
survival 3.5-7
splines 4.4.0
grid 4.4.0
lattice 0.22-5
```

### 注意

- 一連のセッションで利用されたすべてのパッケージの情報が出力されます
   - 探索的な解析を行ったり、いくつかのパッケージを試して比較するなどした場合には、それらすべての情報が出力されます。すなわち、最終的な解析で使用したパッケージ以外の情報も含まれることがあります

- 出力されるパッケージ情報の順序は、ロードされた順序と異なる場合があります
   - これは、`sessionInfo()` 関数の仕様によるものです

- 同じパッケージが複数のバージョンでロードされている場合がある
   - パッケージの依存関係によっては、バージョンの異なる複数のパッケージがロードされている場合があります

## Reactive stat について

弊社では **[ブラウザだけで使える無料統計ソフト Reactive stat](https://www.emuyn.net/stats)** を提供しています。
信頼性の高い R で統計解析し、その結果を AI が解説します！
**Reactive stat** では、すべての R の出力にこの情報が付与されます
ユニークな推奨方法: Outlook の古い PST 一括連絡先リストを VCF に変換する

<p>今日、アドレス帳はデジタル世界の不可欠な要素です。幸いなことに、メール クライアントの Outlook は、すべての連絡先を整理するのに役立ちます。連絡先リストは vCard として保存でき、ほぼすべての電話やデバイスと互換性があります。どこからでもすべての連絡先にアクセスできます。その結果、ユーザーは Outlook の連絡先を vCard にエクスポートしたいと考えています。Softaken vCard エクスポート インポートは、このために役立ちます。</p>
<p>このブログでは、簡単な手順で Outlook の連絡先を vCard として保存する方法を説明します。vCard は、ほぼすべてのコンピューターや電話で機能する小さなアドレス帳です。vCard を使用すると、連絡先を誰とでも簡単に共有できます。</p>
<h2><strong>VCFファイルの利点</strong></h2>
<p>次のセクションでは、vCard ファイルを利用する利点をいくつか説明します。これにより、Outlook の連絡先を vCard にエクスポートする際に役立ちます。</p>
<ul>
    <li>従来の紙の名刺よりも早く連絡先情報を交換したい場合、vCard が最適です。</li>
    <li>追加のソフトウェアを必要とせず、メモ帳などの基本的なツールを使用して vCard を簡単に開くことができます。</li>
    <li>共有も簡単です。コンピューター、タブレット、電話からメール、テキスト メッセージ、その他の任意の方法で送信できます。</li>
    <li>デバイスに関係なく、ほぼすべてのデバイスで vCard を利用できます。</li>
</ul>
<p>Outlook で直接これを行うことはできませんが、連絡先をエクスポートする簡単な方法をいくつか紹介します。できるだけ早くこれらの接続を移動しましょう。</p>
<p><strong>Outlook から連絡先を vCard 形式にエクスポートする方法は 2 つあります。</strong></p>
<p>Outlook の連絡先は、自動と手動の 2 つの異なる方法で vCard として保存できます。まずは手動のアプローチから始め、次にすべてを一度に完了するより迅速なテクニックを紹介します。</p>
<h2><strong>1. Outlookの連絡先を手動でVCFにエクスポートする</strong></h2>
<ul>
    <li>Outlook を開き、まずナビゲーション バーに移動します。</li>
    <li>次に、「People」（Outlook 2013 の場合）または「Contacts」（Outlook 2007 ～ 2010 の場合）を選択します。</li>
    <li>次に、vCard として保存する特定の連絡先を選択します。</li>
    <li>「ファイル」をクリックし、「名前を付けて保存」をクリックします。</li>
    <li>次に、ファイルの保存場所を選択し、名前を付けます。</li>
    <li>さらに、「ファイルの種類」で「vCard ファイル (*.vcf)」を選択します。</li>
    <li>最後に、「保存」を選択して、連絡先を vCard としてエクスポートします。</li>
</ul>
<p>これで、Outlook から vCard への連絡先の手動エクスポートが効果的に完了しました。Outlook の連絡先ファイルが多数ある場合は、上記の戦略を使用するために前述の手順を繰り返す必要があります。また、次のソリューションの手順に従うには、Microsoft Outlook プログラムをダウンロードする必要があります。次の方法を使用して、エクスポート手順を簡単に完了します。</p>
<p>出力 VCF ファイルを取得した後、vCard ファイルに重複がある場合は、Softaken VCF 重複削除 を使用してください。データに影響を与えることなく、重複を簡単に削除できます。</p>
<h3><strong>2. OutlookからVCFへの連絡先の自動抽出方法</strong></h3>
<p>最も効果的で最もよく知られているプログラムは、<strong>Softaken vCard エクスポート</strong> インポートです。ユーザーは、これを使用して、簡単に <a target="_blank" rel="noopener noreferrer" href="https://www.softaken.com/jp/vcard-export-import"><strong>Outlook の古い PST 一括連絡先リストを VCF に変換</strong></a> できます。さらに、プレビュー ボックスを使用すると、ユーザーは転送する連絡先ファイルを選択して調べることができます。さらに、特定の時間枠内で選択的な変換を実行するオプションもあります。このアプリは、すべての Windows バージョンで完璧に機能します。これに加えて、視覚的なユーザー インターフェイスにより、初心者でも簡単に指示に従うことができます。</p>
<h3><strong>vCard を Outlook の連絡先に変換する手順</strong></h3>
<p>あなたの懸念を和らげるために、このウィザードがどのように動作するかについて説明します。</p>
<ul>
    <li>最初に、デスクトップに Softaken vCard エクスポート インポート アプリケーションを保存して起動します。</li>
    <li>次に、vCard に変換したい PST ファイルまたはフォルダを選択します。</li>
    <li>ファイルのプレビューを確認した後、「次へ」をクリックして続行します。</li>
    <li>ファイル形式として「VCF」を選択すると、連絡先が vCard 用に準備されます。もう一度「次へ」をクリックします。</li>
    <li>変換したファイルを保存する場所を選択します。</li>
    <li>最後に、「変換」を押して手順を開始します。</li>
</ul>
<h3><strong>結論、</strong></h3>
<p>Outlook の連絡先が vCard に変換され、使用できるようになりました。使用しているテクノロジに関係なく、誰でもあなたから連絡先を受け取ることができます。一度に 1 つの連絡先について Outlook の連絡先を vCard に変換する手動の方法もありますが、特に転送する連絡先が多数ある場合は、vCard 変換インポートを使用する方がよいことを覚えておいてください。</p>
インターフェースについてめっちゃ感覚的にまとめる ~最後にGoの例もあるよ~

プログラミングを学習する、実装をしているとよく聞くインターフェースという言葉があり、筆者は最初あまりピンと来なかったので、ここでインターフェースについてまとめてみます。

インターフェースとは境界、表面、といった意味があり、プログラミングの世界では、クラスやメソッドの仕様を定義するためのものとして使われます。

本記事では体系的に解説するのではなく感覚的にまとめることを目指します。

## 身近なものに例えてみる

いきなりプログラムの世界のinterfaceを説明するのは難しいので、身近なものに例えてみます。

### 自動販売機

例えば自動販売機は人間がお金を入れて、ボタンを押すと商品が出てくる動きをします。

購入の対象が飲み物でもお菓子でも、自動販売機は同じようにお金を受け取り、商品を出すという動きをします。

これをインターフェースという考え方で表現すると、「お金を受け取りボタンを押す」と「商品を出す」という動きを期待していると考えることができます。

利用する我々からすると、お金を入れてボタンを押すという動きをするだけで、商品が出てくるという動きを期待しているので、その動きをインターフェースとして考えることができます。

ここでのポイントは商品が出てくるまでの動きを知らなくても、お金を入れてボタンを押すという動きをするだけで商品が出てくればそれでいいということです。

### 洗濯機

少しくどいがもう一つ例を上げて抽象度を上げてみます。

洗濯機に対して考えてみます。

我々は洗濯機に対しては洗濯物を入れて、洗剤を入れて、ボタンを押すという動きをするときれいになった洗濯物が出てくることを期待します。

ドラム式でも縦型でも、静音機能やイオンを使っているかどうか、洗濯機の中でどのような動きをしているかに関係なく、洗濯物を入れて洗剤を入れてボタンを押すという動きをするだけで、洗濯物がきれいになるという動きを期待しているので、その動きをインターフェースとして考えることができます。

## プログラムの世界でのインターフェース

さてここまで身近なものに例えてみたので今後はプログラムの世界でのインターフェースを見てみます。

現実世界でのインターフェースは機械を使いましたがプログラムの世界ではクラスやメソッドの仕様を定義するためのものとして使われます。

例えばGoのinterfaceはメソッドの集まりを定義するためのものです。

自動販売機の例で言うと、お金を入れることで商品が出てくるという動きを期待しているので、その動きを定義すると以下のように考えられます。

```go
type VendinMachine interface {
    GetItem(int) string
}

// 飲み物の自動販売機
type DrinkVendingMachine struct {
    Items []string
}

func (d DrinkVendingMachine) GetItem() string {
    return d.Items[0]
}

// お菓子の自動販売機
type SnackVendingMachine struct {
    Items []string
}

func (s SnackVendingMachine) GetItem() string {
    return s.Items[0]
}

```
これらの例では、自動販売機のinterfaceを定義して、飲み物/お菓子それぞれの自動販売機がそのinterfaceを満たすように実装しています。

interfaceを満たすメソッドを実装することで自動販売機のinterfaceを満たすことができ、以下のように利用することができます。

```go

func main() {
    drinkVendingMachine := getDrinkVendingMachine()
    snackVendingMachine := getSnackVendingMachine()

    fmt.Println(drinkVendingMachine.GetItem()) // コーラ
    fmt.Println(snackVendingMachine.GetItem()) // ポテトチップス
}

func getDrinkVendingMachine() VendinMachine {
    return DrinkVendingMachine{Items: []string{"コーラ", "オレンジジュース"}}
}

func getSnackVendingMachine() VendinMachine {
    return SnackVendingMachine{Items: []string{"ポテトチップス", "チョコレート"}}
}

```

ここでのポイントはdrinkVendingMachineやsnackVendingMachineはそれぞれの自動販売機のインターフェースを満たすように実装されているので、それぞれのインスタンスをVendinMachine型として扱うことができています。

仮に各structの中身が入れ替わったとしてもGetItemメソッドがあればそれを利用することができるので、interfaceを使うことで柔軟にプログラムを書くことができます。

これのメリットはDBサーバーを変更したり、APIサーバーを変更したりする際に、特定のメソッドを有するinterfaceを使うことでその変更に対して柔軟に対応することができるということです。

interface(抽象)に依存することで柔軟に変更に対応できるというのがinterfaceのメリットです。

## まとめ

具体的な実装に依存することなく変更に強いプログラムを書くためにinterfaceへの理解を深めましょう！
画像のマジックナンバーを覚えよう！

# マジックナンバーとは
画像ファイルにかかわらず、だいたいのメディアファイルの最初にある、拡張子とは別のファイルの識別子です。

https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B8%E3%83%83%E3%82%AF%E3%83%8A%E3%83%B3%E3%83%90%E3%83%BC_(%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E8%AD%98%E5%88%A5%E5%AD%90)

# なぜマジックナンバー？
マジックナンバーは、拡張子等を残さなくても画像内部に埋め込まれているのでデータがごちゃごちゃしたりしなかったりします。
まあ大体はマジックナンバーなどを使わずMIMEタイプや拡張子を使うでしょう。
# マジックナンバーリスト
| 種類 | 拡張子 | MIMEタイプ | マジックナンバー |
|:-:|:-:|:-:|:-:|
| PNG | .png | image/png | `89 50 4e 47 0d 0a 1a 0a` |
| JPEG | .jpg .jpeg .jpe <br> .jfif .jfi .jif | image/jpeg | `ff d8` |
| BMP | .bmp | image/bmp | `42 4d ('BM')` |
| GIF | .gif | image/gif | `47 49 46 38 39 61 (GIF89a)` <br> 又は `47 49 46 38 37 (GIF87a)` |

気が向いたら別ファイルも作りますので、お願いします。
LeetCode挑戦日記：Day13

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

# [Medium] 1679. Max Number of K-Sum Pairs

整数の配列`nums`と整数`k`が与えられる。
1回の操作では、配列から合計が`k`になる2つの数を選び、それらを配列から取り除く。
配列に対して実行できる最大の操作回数を返してください。

## 素直に解いてみる → NG

### 考え方

1. `nums`の先頭からペアになる要素がないかを確認する
1. ペアになる要素は削除しておき、ペアを見つけた回数を返す

### コーディング

```typescript
function maxOperations(nums: number[], k: number): number {
    let counter = 0;
    while (nums.length) {
        const num = nums.shift();
        const diff = k - num;
        if (diff) {
            const pairIndex = nums.indexOf(diff);
            if (pairIndex !== -1) {
                nums.splice(pairIndex, 1);
                counter++;
            }
        }
    }
    return counter;
};
```

### 結果

Time Limit Exceeded

## 改善：ループ数を減らす

### 考え方

1. 今回はペアを見つけるときにインデックスを覚えておく必要がない
1. ソートすることで左右からチェックするだけでいける

### コーディング

```typescript
function maxOperations(nums: number[], k: number): number {
    let counter = 0;

    const sortedNums = nums.filter((num) => num < k).sort((a, b) => a - b);
    let left = 0;
    let right = sortedNums.length;

    while (left < right) {
        const sum = sortedNums[left] + sortedNums[right];
        if (sum < k) {
            left++;
        } else if (sum === k) {
            counter++;
            left++;
            right--;
        } else {
            right--;
        }
    }

    return counter;
}
```

### 結果

Runtime：113ms
Beats 78.56%

Memory：63.03MB
Beats 44.95%
OWASP WebGoatを触ってみた

# はじめに

[前回の記事](https://qiita.com/oreha_gao/items/f4ad5a459c91e3023843 "ペネトレーションテストについてあらためて調べてみた
")に引き続き、ペネトレーションテスト関連の取り組みでWebGoatを触ってみることになったので、ローカルマシン上で動かすまでの簡単なメモ等をまとめました。

# WebGoatとは？

WebGoatは意図的に安全性を低くしたWebアプリケーションで、一般的なオープンソースコンポーネントを使用する Javaベースのアプリケーションでよく見られる脆弱性をテストすることができます。

:::note alert
WebGoatの使用は教育目的のみに限られます。
WebGoatで取り扱う内容を許可なく第三者が管理している端末へ試みると、不正アクセス等に該当する可能性がありますので、許可を得た端末や自身の端末に対してのみ使用するようご注意ください。
:::


https://owasp.org/www-project-webgoat/

# 環境

今回はwsl2上で動作しているUbuntuにDockerとJavaを入れて構築しました。
（それぞれの細かいインストール手順は割愛します）

- OS: Windows 10
- WSL: WSL 2
- Ubuntu: Ubuntu 22.04.3 LTS
- Docker: version 26.1.1
- Java: openjdk version "21.0.3"

# 手順

WebGoatはDocker Hubにイメージが公開されていますが、カスタマイズして使いたいためローカルでイメージをビルドする方法としています。

1. Ubuntuの任意のディレクトリにWebGoatのリポジトリをクローンします

    ```bash
    $ git clone https://github.com/WebGoat/WebGoat.git
    ```

2. クローンしたリポジトリに移動し、ライブラリをインストールします

    ```bash
    $ cd WebGoat
    $ ./mvnw clean install
    ...
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  03:52 min
    [INFO] Finished at: 2024-xx-xxTxx:xx:xx+09:00
    [INFO] ------------------------------------------------------------------------
    ```

3. コンテナイメージを作成します

    ```bash
    $ docker build . -t webgoat
    [+] Building 60.8s (9/9) FINISHED
    ...
    $ docker images
    REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
    webgoat               latest    1abc00efghi1   xx seconds ago   403MB
    ```

4. コンテナを起動します（起動が完了するまで数分かかります）

    ```bash
    $ docker run -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 webgoat:latest
    ```

5. 任意のWebブラウザから`http://127.0.0.1:8080/WebGoat/`にアクセスします

特に問題が発生していなければ↓のようにWebGoatのログイン画面が開けるはずです！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1278906/317f4d2f-dbc9-b946-09a3-df79500ca2f5.png)


# おわりに

今回はWebGoatを動作させるまでの手順を簡単にまとめてみました！
次はWebGoatの課題の内容や、カスタマイズする方法等について記事にまとめてみようと思います！
VFXGraphとParticleSystemで大量に配置した際の処理負荷を比較してみた

## 概要
VFXGraphを大量に配置した際処理負荷を計測するとCPU負荷が高かったのでParticleSystem(Shuriken)と比べて処理負荷が軽いのか気になったので調査してみました

## 環境
Unity2023.2.61f

## 調査内容
生成するエフェクトプレハブの数は1000個

パーティクルの数が0の状態とある程度パーティクルの数を出したものをVFXGraphとShurikenでCPU負荷を比較する

パーティクルの数や寿命などはほぼ一致させてます

![49d7cb64-3083-4ab4-bcb3-f45835278585.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/739f9929-0851-7303-e1a9-6203ef41f55e.gif)

VFXGraphの設定

![14b7bf58-6f58-4d2d-8059-ac0c4187d480.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/67ac7588-090e-c201-0aad-62d8708ea244.png)

ParticleSystemの設定

![c3fef1c5-0635-4d21-b322-1887a0646449.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/e322d455-65e0-bf81-497e-667490080cf6.png)


##  調査結果

### パーティクルの数が0の場合

 | VFXGraph | ParticleSystem |
|:-:|:-:|
|  **0.72ms** | **0.83ms + 0.34ms = 1.17ms**  |
| ![77d14f91-2ca8-4c17-98ba-d5c59b72c054.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/ef144b49-d6ea-e096-5bdd-6ed878b401d2.png)  |  ![7ef2f6bc-24db-4dce-a409-fd7c9dee2217.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/c529b10e-f317-f6ba-c299-004804d86dd0.png)  |
   

### パーティクルの数がある程度出したの場合
VFXGraphの方が重いです

 | VFXGraph | ParticleSystem |
|:-:|:-:|
|  **4.5ms** | **0.94ms + 0.36ms = 1.3ms**  |
| ![b8a33f74-bf35-44a2-8e4e-4821957bc064.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/1bbdecf0-d7d0-f68c-6bdf-9e6bd52ee5bc.png) | ![e8690ce5-4512-43e2-984f-ef922800072f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/d8787848-dbc1-867c-a7b2-d8108270e3a2.png) |
 
VFXGraphは同じVFXGraphならbatch処理することで処理負荷軽減できるので出来るのでそちらも調査します

参考

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@17.0/manual/Instancing.html


![355311e3-9dbe-4c08-b69a-0ba849812ca7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/a566a9fd-76b8-d976-3054-63960ae4618b.png)


同じVFXGraphをbatch処理した場合

**0.68ms**

![7650e640-300d-4518-bfa6-87cf745b04ae.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/72086c57-01d1-4dd3-81b7-88dd5309d8ff.png)

## なぜVFXGraphは大量に配置すると重いのか
コマンドバッファのGPUに情報を送る処理が処理負荷になってます

これはFraneDebuggerで確認することが出来ます

![245dbcc7-1104-4240-a2bb-11218a2d6979.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/6a329b65-688e-cbdd-20c0-8abefa8c7be2.png)


batch処理だとGPUに情報を送る処理がまとまる分処理負荷が軽くなってるみたいです

![45783ae5-f1ed-4e89-b244-3f97d9c72ffc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819930/2ac9baad-2edb-c48f-2e13-2df25de8767c.png)


## 結論
・1つのエフェクトプレハブで大量にパーティクルを出す場合や同じエフェクトプレハブを大量に出す場合はVFXGraphの方が処理負荷が軽いです。

・複数の種類で大量のエフェクトプレハブを出す場合はParticleSystemの方が処理負荷が軽くなりそうです。
闘魂Elixir ーー AtCoder Beginner Contest 334(A)をElixirで楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>


# はじめに

[AtCoder Beginner Contest 334](https://atcoder.jp/contests/abc334)を[Elixir](https://elixir-lang.org/)で解いてみます。

[AtCoder](https://atcoder.jp/)を解くのが趣味で、休憩時間に解いているという若い人がいて、それってすごい意識の高い休憩時間の過ごし方だと思って、私も真似してみることにしました。


# [AtCoderをElixirでやってみる](https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01)

入力の読み取り方や解答の作り方は、別の記事にまとめています。


https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01

ご参照くださいませ。

[Elixir](https://elixir-lang.org/)で[AtCoder](https://atcoder.jp/)を楽しむためには、エントリポイントを`Main.main/0`にする必要があります。つまり`Main`モジュールを作って、その中に`main/0`関数を定義するわけです。

# [A - Christmas Present](https://atcoder.jp/contests/abc334/tasks/abc334_a)

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。


<details><summary>私の解答</summary>

_問題文を読んでいることを前提にひとこと解説をしておきます。_


入力値の大小比較をする問題です。関数のガード節で場合分けするように実装してみました。

```elixir
defmodule Main do
  def main do
    [b, g] =
      IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)

    solve(b, g)
    |> IO.puts()
  end

  def solve(b, g) when b > g, do: "Bat"

  def solve(_b, _g), do: "Glove"
end
```




</details>




---

# さいごに

[AtCoder Beginner Contest 334](https://atcoder.jp/contests/abc334)を[Elixir](https://elixir-lang.org/)で解くことを楽しみました。

あなたのお好きなプログラミング言語でお楽しみください。

---


**闘魂**とは、  **「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダァー！}$</font></b>
ConoHa VPSのサーバー再構築において、躓いたところ

## 動作環境
ConoHa VPS、Ubuntu 20.04.6
## 起きた問題
サーバー構築の復習をするために、ConoHa VPSを再構築すると、パスワードを使ったsshログインができなくなってしまいました。
一周目はそんなことなかったので、戸惑いました。
## 解決方法
パスワードを使った認証は許可されていました。
```ruby:/etc/ssh/sshd_config
PasswordAuthentication yes
```

調べていくうちに、/etc/ssh/sshd_config.d/50-cloud-init.confファイルというものがあり、どうやらそこに問題がありそうだという事なので、確認してみるとパスワードを使った認証を禁止しているコードを発見！
```ruby:/etc/ssh/sshd_config.d/50-cloud-init.conf
PasswordAuthentication no
```
この設定を`yes`に変えると、無事パスワードを使ったSSHログインができました。
おそらく、ConoHa VPSのサーバーを再構築した時にSSH KEYのオプションを「登録済みキー」か「新規キー登録」を選んだので、認証鍵を使ったSSHログインができるように、設定してくれてるんですね！

## 参考にした記事
https://zenn.dev/ochanoma/articles/f354be22ecb4cb
こちらの記事がなければ、解決できなかったと思います。助かりました。ありがとうございました！
エンジニア2年目が世界一流エンジニアの思考法を読んだ！

初めまして！元公務員エンジニアのガッキーです。
今回は[「世界一流エンジニアの思考法」](https://www.amazon.co.jp/dp/4163917683)を読んで学んだことをまとめてみました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671845/4d8369ab-08d2-0b24-fa5e-68d2f45c55d5.png)

この本を読んだときは、勤務する受託系企業の案件が炎上していて、
頭が混乱していたタイミングで「もうどうしたらいいんだ！」となっている時で
本書を読んで色々と救われた気分になりました。

特に印象に残っている３つまとめてみました！

# 1.Be Lazy 怠惰であれ！👌

第2章 「アメリカで見つけたマインドセット」に書かれている内容で、
怠惰を日本語に直訳すると「すべきことを怠ける様子」という意味ですが
アメリカの使われ方としては「より少ない時間で価値を出す」考え方だそうです。

具体的なところでいうと、

### 「優先順位の考え方」

ここに大きな違いがありました。
日本の優先順位の考え方は１～５あるタスクの重要なタスクから順番を決めて作業をします。
一方アメリカの優先順位の考え方では最重要である1つ決めて他はやらない。
このように不要なタスクはバサバサ切っていくそうです。

### 「時間の使い方」

アメリカの考え方では作業時間を固定して価値を最大化させることにあります。
日本のあれもこれも「すべき」マインドだと、あーこれもあれも・・・と時間が伸びてしまう傾向がありますが、アメリカでは決められた作業時間のなかで価値を生み出すことにフォーカスするため、
今日はこの「２つ」限られた時間で作業しようというマインドです。

# 2.脳の負荷を減らす🧠

エンジニアの仕事・・・頭使いますよね！？
僕はエンジニア2年目ですが日々脳がパンパンになる感覚があります！

僕は書店で目次の中に「脳の負荷」を減らすと見かけて、この本を購入しました！

具体的に紹介されている手法を見ていきましょう！

### コードリーディングは極力読まないこと

牛尾さんも当初は、プログラムを理解するため端から端まで実装を読んでいたそうですが、
脳疲労を感じるわりに頭に入らないことを感じていたそうです。
技術イケメンのアドバイスは、プログラムはきちんと実装されていることを信じ。
「極力読まないようにして構造を理解する」というものでした。

他にも

### マルチタスクはしない

これはギクッとするひとことで、マルチしまくりでした。
例えば、
- ひとつのタスクが割り振られたら、他のコードやバグが気になり、別のコード修正をしている
- エラーをネットで検索していたら気づいたらネットサーフィンしていた
- 会議中にタスクをこっそり進めていた

マルチタスクは生産性をかなり下げることが、色々な研究で証明されていて、
対策として、

- 今手を付けている作業を１つに限定する
- ３０分から１時間は、そのことのみに集中する
- 終わったタスクに関係するブラウザのタブは閉じる

これらが有効であるということが書かれていました！


またほかにも脳の負荷を減らすために

- 瞑想をする
- ディスプレイから離れる
- しっかりと睡眠をとる

など実践されているそうです！

# 3.不確実性を受け入れる😕

第2章に書かれている内容でシステム開発は、
予定どおりにいくことがまず無い！と書かれています。

- 「納期絶対の神話は捨てる」

システム開発は炎上したり不具合がみつかったりと
実際に見積もったバッファ30％を超えることはよくあること！

これを目にした僕は「これだよ！！」と感じて
まさに炎上している案件は確実に納期に間に合わないし、
見積を大幅に超えて、進めれば進めるほど「コレもやらなきゃ」なんて課題が増える一方でした！

**さて、じゃあどうすればいいか。**

> 納期を固定したまま、提供する物量を調節することがベスト間に合わないものは次に回すか、やめる。

このような策を提案されています。

システム開発には「予定どおりにいくことがない」という言葉はハッとさせれらました。
異業種から転職してきた自分は常にシステムが仕様通り、確実にクリアしていくべきという意識で仕事していたので、バグや大きな遅延が起きるといつもハラハラしていました。僕が努めているお客さんに納期の約束をしている、受託系企業ではこの課題にどのようにアプローチしていくか深堀が必要だと感じました。

# まとめ🖊️

ご覧いただきありがとうございました！
本書を読んで、書ききれないほどの学びがたくさんあったのですが、
じゃあ具体的に何やろうか？
と考えたときに受託系企業だとハードル高いななんて感じることも多々ありました。

なので僕はとりあえず同僚に**本書を読むこと勧める**というアクションをとることをしました！笑

何か気になる点や、おかしな点ありましたらお気軽にコメントください！
Element PlusのExposesを理解した

いつもelement plusを使っていると、コンポーネント内の子要素を操作することに手間がかかっていた。

ドキュメントのコード例では書いていなさそう。

毎回ref指定して`querySelector`だったり、Vanilla JSでDOM操作するしかないと思いつつ作業していたが、ドキュメントで以下のようなものを発見した。

#### `cascader`のドキュメント

![スクリーンショット 2024-06-17 18.16.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754242/fee4b8b3-323d-a457-8f3c-3f7aed07541f.png)

https://element-plus.org/en-US/component/cascader.html

Descriptionを`cascader panel ref`や`cascader content ref`で書いているということは、要素をrefで渡しているように見える。

`Exposes`項目に入っているので、vueの`defineExpose`を指すと考えた。
`defineExpose`は子要素から親要素に渡すためのもので、refから`.`でその要素を指定すると使うことができる。

## コード例

```ElementPlus.vue
<script setup lang="ts">
const cascader = ref();

const suggestedElement = categoryCascader.value.contentRef.querySelector(
    '.el-cascader__suggestion-item',
) as HTMLElement;

onMounted(() => {
    suggestedElement.focus(); // mount時にcascaderにfocusする
});
</script>
<template>
    <el-cascader ref="cascader"></el-cascader>
</template>
```

## 終わりに
ドキュメントに何か書いてあるのに今必要なものだけに集中すると、時間の無駄をしてしまうことがわかった。ドキュメント大事。
Ginを使ってAPIサーバーを立ち上げてみよう

# Gin って？

GinはGo言語でウェブAPIを作成するためのフレームワークです。
簡単にかけるのにパフォーマンスも良い！
そんな理由で人気のあるフレームワークです。

# 使い方

俯瞰して見られるように全体のコードを乗せておきます。
サッと流し見をしてから、詳細を見ていきましょう。

```Go
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

type User struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

var users []User

func main() {
	server := gin.Default()

	server.GET("/score", getUsers)   // GetのAPIを登録
	server.POST("/score", addScores) // PostのAPIを登録

	err := server.Run(":8080")
	if err != nil {
		fmt.Println("Error starting server")
		return
	}
}

func getUsers(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"users": users,
	})
}

func addScores(c *gin.Context) {

	var user User
	err := c.BindJSON(&user) // リクエストのボディを構造体に変換
	if err != nil {
		fmt.Println("Error reading body")

		c.JSON(http.StatusBadRequest, gin.H{ // エラーがあった場合はエラーメッセージを返す
			"message": "Error reading body",
		})
		return
	}

	users = append(users, user) // ユーザーを追加
	c.JSON(http.StatusOK, gin.H{
		"message": "Add User",
	})
}
```

# サーバーを立ち上げる

```Go
    server := gin.Default()
    err := server.Run(":8080")
    if err != nil {
        fmt.Println("Error starting server")
        return
    }
```

この部分ではサーバーを立ち上げていて、`:8080` でポートを指定しています。
このコードを実行すると、`http://localhost:8080` で自動的に立ち上がります。

```Go
	server.GET("/score", getUsers)   // GetのAPIを登録
	server.POST("/score", addScores) // PostのAPIを登録
```

この部分では、`/score` というエンドポイントに対してGETとPOSTのAPIを登録しています。
GETのリクエストが来たら `getUsers` 関数が呼ばれ、POSTのリクエストが来たら `addScores` 関数が呼ばれます。

```Go
func getUsers(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
        "users": users,
    })
}
```

なぞの `gin.Context` というのは、リクエストやレスポンスに関する情報を持っている構造体です。
これを使って、リクエストに対してレスポンスを返していきます。
基本的な使い方はこれだけですが、詳しい中身を知りたい方は[こちら](https://pkg.go.dev/github.com/gin-gonic/gin@v1.10.0)を参照してください。
ここらへんはフレームワークの使い方なので暗記になりがちですね。

```Go
	var user User
	err := c.BindJSON(&user) // リクエストのボディを構造体に変換
```

この部分では、リクエストのボディを構造体に変換しています。
もしも何かしらのエラーがあった場合は、`err` にエラーが入るので、それを使ってエラーハンドリングを行います。
Railsでいいね機能：ビューファイル中で使用しているいいね判定メソッドでn+1問題が発生した時の対処法


## 読んで欲しい人
- Railsでいいね機能を実装していて
  - ビューのループ中でクエリを発行するメソッドを使用している人
  - SQLクエリがたくさん出てきて、n+1問題が発生している人
- 過去の自分
## 動作環境
- MacOS 14.5
- ruby 3.3.0
- Rails 7.1.3.3
- psql (PostgreSQL) 14.11

## 作っているアプリの構造
### 概要
- 小さいX（旧ツイッター）みたいなアプリ
    - ログイン機能
    - 短文の投稿機能
    - いいね機能
### テーブル設計
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819522/487a583f-ba66-738d-616c-8690cb94d7da.png)
## エラー・課題
```sql
app/models/user.rb:23:in `already_liked?'
16:48:02 web.1  |   Rendered posts/_like_btn.html.haml (Duration: 1.6ms | Allocations: 609)
16:48:02 web.1  |   Rendered posts/_follow_btn.html.haml (Duration: 0.0ms | Allocations: 12)
16:48:02 web.1  |   Like Exists? (0.3ms)  SELECT 1 AS one FROM "likes" WHERE "likes"."user_id" = $1 AND "likes"."post_id" = $2 LIMIT $3  [["user_id", 2], ["post_id", 5], ["LIMIT", 1]]
```
↑
これがめっちゃ出てくる。
クエリがたくさん発行されてn+1問題になってしまっている
## 原因
- いいねボタンを表示する時に`already_liked?`が何回も実行されて、投稿の回数分のクエリが発行されてしまっている
### いいねボタンを表示する仕組み
```ruby:_like_btn.html.haml
# いいねボタンを表示するファイル
-if current_user.already_liked?(post)
  = button_to post_likes_path(post_id: post), method: :delete do
    %i.fa-regular.fa-hear　#　→　いいねしてない時のアイコン
- else
  = button_to post_likes_path(post_id: post), method: :post do
    %i.fa-solid.fa-heart #　→　いいねしてる時のアイコン
```
### already_liked?メソッド
- 自分がその投稿をいいねしているのか、していないのかを判定するメソッド
```ruby:user.rb
# モデルファイル
def already_liked?(post)
  likes.exists?(post_id: post.id)
end
```

#### exists?メソッドとは

- 指定した条件のレコードがデータベースに存在するかどうかをture/falseで返すメソッド

- SQLを発行するメソッド

```ruby
# 使い方
Like.exists?(post_id: 3)

# 発行されるSQL
#SELECT 1 AS one FROM "likes" WHERE "likes"."post_id" = $3 LIMIT $1
```

## 解決方法

- 事前に配列でlikesテーブルからpost_idの配列を取得して、include?メソッドでいいね判定を行うようにする

```ruby:likes_controller.rb
#コントローラ
def index
  @liked_post_ids = current_user ? current_user.likes.pluck(:post_id) : []
end
```

```ruby: view
#ビュー画面で使うとき
-if liked_post_ids.include?(post.id)
  = button_to post_likes_path(post_id: post), method: :delete do
    %i.fa-regular.fa-hear　#　→　いいねしてない時のアイコン
- else
  = button_to post_likes_path(post_id: post), method: :post do
    %i.fa-solid.fa-heart #　→　いいねしてる時のアイコン
```

#### pluckメソッドとは

- テーブルから指定したカラムを取得するクエリを送信できる

```ruby
# 使い方
Like.pluck(:post_id)

# 発行されるSQL
#Like Pluck (0.9ms)  SELECT "likes"."post_id" FROM "likes"

# 戻り値：post_idを配列にしたもの
[1, 2, 3, 5]
```


※current_userがない時にから配列を返している理由
- nilに対して`.include?`をするとエラーになってしまうため

## 学び

- コードを記述するときは、そのメソッドがどんなクエリを発行しているのか？を気にして書くこと

- DBとのやり取りを意識してコードを書くこと

## 参考記事

https://qiita.com/k-o-u/items/31e4a2f9f5d2a3c7867f

https://pikawaka.com/rails/exists

https://qiita.com/RIN_HM/items/968abd9e31df6631a3ed

https://zenn.dev/ganmo3/articles/c071ba9aecaa51

https://railsguides.jp/active_record_querying.html