OmniAICreator/Qiita-1.07M huggingface dataset:
MyBatisのcollectionの書き方

MyBatisの`collection`の書き方でつまづいたので備忘録として残しておく。
今回はmyBatisの設定やcollection以外の書き方には触れません。

MyBatisでは、一対多の関係の場合は以下のようにマッピングできる。
例えばusersテーブルとbooksテーブルが一対多の関係にあるような場合です。

#### エンティティ：User

```java:User.java
public class User {
    private Integer id;
    private String name;
    private List<Book> bookList;
}
```

#### エンティティ：Book
```java:Book.java
public class Book {
    private String title;
}
```
#### Mapper XML：userMapper

```xml:userMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">

    <!-- ユーザーと所有している本を取得 -->
    <select id="selectUserWithBooks" resultMap="UserWithUserBooks">
        SELECT u.id as userId, u.name as userName, 
              b.title 
        FROM users u
        LEFT JOIN books b ON u.id = b.user_id
    </select>

    <!-- ResultMapで一対多のマッピング -->
    <resultMap id="UserWithBookMap" type="com.example.model.User">
        <id column="userId" property="id"/>
        <result column="userName" property="name"/>
        
        <!-- 一対多の関係をマッピング -->
        <collection property="books" ofType="com.example.model.Book">
            <id column="bookId" property="bookId"/>
            <result column="title" property="title"/>
        </collection>
    </resultMap>

</mapper>
```

一対多のマッピングの場合、調べたら上記のようなxmlの書き方が出てきて実際に試してみたが、自分の環境では、以下のようにエラーが出てしまった。
```
The element type "resultMap" must be terminated by the mathing end-tag"</resultMaP>" 
Remove "</collection>"
```

試しに<<//collection>を削除してみたがダメだった。
以下のように修正する必要があった。

```xml:userMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">

    <!-- ユーザーと所有している本を取得 -->
    <select id="selectUserWithBooks" resultMap="UserWithUserBooks">
        SELECT u.id as userId, u.name as userName, 
              b.title as title 
        FROM users u
        LEFT JOIN books b ON u.id = b.user_id
    </select>

    <!-- ResultMapで一対多のマッピング -->
    <resultMap id="UserWithBookMap" type="com.example.model.User">
        <id column="userId" property="id" jdbcType="Integer"/>
        <result column="userName" property="name" jdbcType="String"/>
        
        <!-- 一対多の関係をマッピング -->
        <collection property="books" resultMap="bookResultMap">
    </resultMap>

    <resultMap id="bookResultMap" type="com.example.model.Book">
        <result column="title" property="title" jdbcType="String"/>
    </resultMap>

</mapper>
```

自分のように`collection`の書き方で躓いた方には参考にしていただきたい。
XSS、CSRFが覚えられないのでまとめてみた

# はじめに

Webアプリ開発を学習する上でXSS、CSRFよく聞きますが、フレームワークがうまい具合に対処してくれていたので、結局わからないまま時が過ぎました。
そこで今回は、これらの脅威をまとめてみようと思います。

# XXS(クロスサイトスクリプティング)

攻撃者がウェブページに悪意のある**スクリプト（JavaScriptなど）を埋め込む**攻撃。
他ユーザーがアクセスした時に、スクリプトが実行され、ユーザの情報を盗んだり、セッションをハイジャックされる。

## 攻撃の仕組み

- ユーザー入力の未検証: ユーザーが入力したデータ（例：フォームやコメント欄）をそのまま表示する際に、スクリプトコードを含んだデータが実行されてしまう。
- スクリプトの埋め込み方法: 攻撃者は、フォームやURLパラメータにスクリプトコード\<script>タグを埋め込んでWebページに送信する。このスクリプトがページ内で実行されることで、攻撃が成立。

## 誰が被害を受けるか
主にWebアプリケーションを利用している一般のユーザー。
## 被害例
- セッション情報の流出: 攻撃者がユーザーのセッションIDを取得し、ログイン状態を乗っ取る。
- 個人情報の流出: ユーザーが入力したクレジットカード情報やパスワードが盗まれる。

# CSRF（クロスサイトリクエストフォージェリ）

攻撃者がユーザーの認証情報を使って、ユーザーが意図しない**リクエストをWebアプリケーションに送信させる**攻撃です。ユーザーがログインしている状態で悪意のあるリンクやフォームをクリックさせることで、攻撃者はユーザーの権限を持つリクエストを不正に送信できます。

## 攻撃の仕組み

- 認証された状態でのリクエスト送信:ユーザーがログインしている状態で、攻撃者が悪意のあるリンクや画像を埋め込んだWebページを提供します。ユーザーがそのページを訪問すると、攻撃者はユーザーの権限で不正なリクエストを送信させることができる。  
- リクエストの偽造方法: 攻撃者は、ターゲットのWebアプリケーションに対して、ユーザーが意図しないリクエスト（例えば、金銭送金やアカウント変更）を送信させる。  

## 誰が被害を受けるか
他サービスにログイン状態のユーザー。

## 被害例
- 金銭送金: ユーザーが銀行にログインしているとき、攻撃者が不正な送金リクエストを送信させ、金銭を盗む。
- アカウント設定の不正変更: 攻撃者がユーザーのアカウント設定（メールアドレス変更など）を勝手に変更させる。
pywintypes.error: (2, 'CreateFile', '指定されたファイルが見つかりません。')  During handling of the above exception, another exception occurred:の対処法

<h2>症状</h2>
docker-compose buildやった際に、下記のエラーが発生しました。

```terminal:error
docker-compose build
Traceback (most recent call last):
  File "docker\api\client.py", line 214, in _retrieve_server_version
  File "docker\api\daemon.py", line 181, in version
  File "docker\utils\decorators.py", line 46, in inner
  File "docker\api\client.py", line 237, in _get
  File "requests\sessions.py", line 543, in get
  File "requests\sessions.py", line 530, in request
  File "requests\sessions.py", line 643, in send
  File "requests\adapters.py", line 439, in send
  File "urllib3\connectionpool.py", line 670, in urlopen
  File "urllib3\connectionpool.py", line 392, in _make_request
  File "http\client.py", line 1255, in request
  File "http\client.py", line 1301, in _send_request
  File "http\client.py", line 1250, in endheaders
  File "http\client.py", line 1010, in _send_output
  File "http\client.py", line 950, in send
  File "docker\transport\npipeconn.py", line 32, in connect
  File "docker\transport\npipesocket.py", line 23, in wrapped
  File "docker\transport\npipesocket.py", line 72, in connect
  File "docker\transport\npipesocket.py", line 52, in connect
pywintypes.error: (2, 'CreateFile', '指定されたファイルが見つかりません。')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "docker-compose", line 3, in <module>
  File "compose\cli\main.py", line 81, in main
  File "compose\cli\main.py", line 200, in perform_command
  File "compose\cli\command.py", line 60, in project_from_options
  File "compose\cli\command.py", line 152, in get_project
  File "compose\cli\docker_client.py", line 41, in get_client
  File "compose\cli\docker_client.py", line 170, in docker_client
  File "docker\api\client.py", line 197, in __init__
  File "docker\api\client.py", line 221, in _retrieve_server_version
docker.errors.DockerException: Error while fetching server API version: (2, 'CreateFile', '指定されたファイルが見つかりません。')
[58972] Failed to execute script docker-compose
```

<h2>解決方法</h2>
Docker for Windowsの再起動をしたら解決しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/d0b221f1-c9e1-3d49-080a-cd7ce80e0f4f.png)

<h2>参考</h2>

https://hrroct.hatenablog.com/entry/2022/03/25/095404
Time to Upgrade? Apple Declares These iPhones 'Vintage'

Apple has revised its list of vintage and obsolete products again. The list now includes the iPhone XS Max, iPhone 6s Plus, and several Apple Watch Series 2 variants.

Products that Apple stopped selling over five years ago are classified as "vintage." The iPhone XS Max and iPhone 6s Plus, now designated as vintage, were originally launched in 2018 and 2015, respectively. Despite the fact that these phones were sold three years apart, the iPhone 6s Plus remained available for purchase considerably longer than the XS Max, which is why they are being added to the vintage list simultaneously.

![22.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937793/2edaad4d-7084-dd14-fdb4-5eecf520c488.jpeg)

An Apple product discontinued more than seven years ago may be qualified as "obsolete." The Apple Watch Series 2 in all its various forms—38mm, 42mm, aluminum, stainless steel—is now subject to obsolescence. Originally launched in 2016, it enjoyed a fairly long lifespan, just like the MacBook models that Apple added to its obsolete list last month.

Products designated as "vintage" may be eligible for repair service from Apple and authorized service partners, depending on parts availability. There's no guarantee that Apple will have a replacement screen for your vintage iPhone 6S Plus. Obsolete products, including the Apple Watch Series 2 models, are no longer eligible for Apple hardware service, and service providers cannot order parts for them. This effectively marks the end of official repair options for these devices, though you may still perform DIY repairs or get help from an unauthorized service technician.

An exception exists for some obsolete models of MacBook, which may qualify for an extended battery-only repair up to 10 years after the product's last sale date, subject to parts availability. Unfortunately, this exception does not apply to the iPhones or Apple Watches that were added to Apple's vintage and obsolete lists today.

Source: Apple via 9to5Mac
【VSCode】GitHub Copilotを使用してVSCodeの設定を変更する方法

VS Code Commander拡張機能を使用することでGitHub Copilotを使用してVSCodeの設定変更やコマンドの検索ができます。

https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-commander

## 設定の変更

`@commander`に続けて変更したい設定を記述することでVSCodeの設定が変更されます。
「Undo」ボタンをクリックすれば変更された設定を簡単に戻せます。

![名称未設定.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/a6a082f4-7601-7b66-2068-6a64a9261cef.gif)

## コマンドの検索

`@commander`に続けて検索したいコマンドを記述することでコマンドへのリンクが表示されます。
簡単にコマンドのショートカットキーを変更できます。

![名称未設定3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/8c136772-d9a8-0b87-db23-6811f31f689e.gif)

## コマンドの実行

commander`を先頭に記述し、実行したい操作を入力することでコマンドが実行されます。
以下のGIFでは新規ウィンドウを開いています。

![名称未設定 22.35.52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/1703154d-d6c1-ca6a-12ee-991e8bcd3bcc.gif)
AWS SAP-C02を3年ぶりに受けてみた

### 感想

更新試験が私が調べた所無かったので、再度SAP-C02を一から勉強した感想で言えば、3年ぶりとあって、殆ど忘れている、そして知らないサービス、及び変更が結構あった。お陰で当初2週間勉強して再試験を受けるつもりが、全然勉強が終わらず1週延期してしまいました（前回の勉強期間は1週間。ただしその前にSAA勉強していた）

結果は800点ぐらいでギリ合格

試験自体の傾向は、ここ最近のAWSの実情を反映して、ハイブリッドクラウド関連や、オンプレ側にAWSサービスの拡張するケース、MS系のオンプレからの移行、コストカットなど試験問題自体、事例として個人的には楽しめた。っが、問題も長いし、回答群も長い。視力や集中力が衰えた身としては結構きつかった。
面倒くさくなって、時間は100分ぐらい余ってたけど切り上げで終了した。

### 勉強方法
勉強方法はひたすら下記サイトの問題集の設問と正解回答を見る（覚える）だけで問題は解かないやり方。

https://cloud-license.com/

問題が多いので感覚的にAWSのベストプラクティスが何かが見えてくる。

ただし前提知識としてLPIC3、CCNA,Oracle Silverぐらいの知識レベルが無いとこの手法でやっても落ちる可能性有り。

実は Azure Exertの更新試験もこのタイミングで合ったのですが、諦めました。
試験は週一間隔で受けるもんじゃ無いですね。最近の資格試験は更新があるので、自分のクビを絞めてしまった。

元々AWSの試験に関する記事も出そうかなと思っていましたが、正直余裕がないので、まずは貯まっているオンプレ slurm x aws Parallel cluster連携の記事と、ansibleの記事を来週ぐらいから頑張って書いて行く予定
代入と参照とコピー

# 参考図書

Python3エンジニア認定データ分析試験を受けてみました。
データ分析のモデルを動かしていくうえでの基礎となる知識を
体系的に学ぶことができました。とてもいい機会でした。

内容のなかの一部（とても一部）である代入と参照とコピーの違いについて
今回の試験で整理できたので、
その部分だけ自分なりに書いて残しておきます。
詳しい内容については教科書を参照ください。

:::note 
- 教科書
[Pythonによるあたらしいデータ分析の教科書（翔泳社）](https://www.shoeisha.co.jp/book/detail/9784798158341 "翔泳社のページ")
- 一般社団法人Pythonエンジニア育成推進協会のページ
[公式サイト（データ分析試験）](https://www.pythonic-exam.com/exam/analyist)

:::

## 代入と参照とコピー

Pythonの値はすべてオブジェクト。
変数は、オブジェクトを参照する「オブジェクトID」を保持して、変数から値（オブジェクト）を参照する。

### a1 = aで代入する場合

変数aが保持しているオブジェクトIDが変数a1にも代入され、同じオブジェクトを参照（共有）する。

```Python
a = np.array([1, 2, 3])
a

## 出力結果
array([1, 2, 3])
```

```Python
a1 = a
a1

## 出力結果
array([1, 2, 3])
```

```Python
a1[1] = 5
a1

## 出力結果
array([1, 5, 3])
```

```Python
a

## 出力結果
array([1, 5, 3])
```

※a1 = a の代入で、変数aが保持しているオブジェクトIDが変数a1にも代入されるだけで、オブジェクトはコピーせずに共有するため、変数aが参照しているオブジェクト内容を変更したあと、変数a1が参照しているオブジェクト内容を表示すると変更された内容が表示される

### copyメソッドでコピーする場合

```Python
a2 = a.copy()
a2

## 出力結果
array([1, 5, 3])
```

```Python
a2[0] = 6
a2

## 出力結果
array([6, 5, 3])
```

```Python
a
## 出力結果
array([1, 5, 3])
```

copyメソッドでコピーすると、a2をいじってもaの配列に反映されない

### ravelは参照、flattenはコピー
```Python
c1 = np.array([0,1,2,3,4,5])
c2 = c1.reshape((2,3))
c2

## 出力結果
array([[0, 1, 2],
       [3, 4, 5]])
```
c3,c4にそれぞれ別の値を上書きしてみる
```Python
c3 = c2.ravel()
c4 = c2.flatten()
c3[0] = 6
c4[1] = 7

## 出力結果
```

```Python
c3

## 出力結果
array([6, 1, 2, 3, 4, 5])
```

```Python
c4

## 出力結果
array([0, 7, 2, 3, 4, 5])
```

```Python
c2

## 出力結果
array([[6, 1, 2],
       [3, 4, 5]])
```

※c2はc3の変更（ravel）の影響を受けているが、c4の変更（flatten）の影響は受けていない
→ravelは参照（つまり同じオブジェクトとして扱われる）
→flattenはコピーとなる


### Pythonの標準のリストとNumpyのコピーは異なる

Python標準のリスト：浅いコピーと深いコピーを区別して扱う。
スライスは浅いコピーで、コピーした先の浅い層をいじってもコピー元には反映されない

```Python
py_list1 = [0,1]
py_list2 = py_list1[:]
py_list2[0] = 2
print(py_list1)
print(py_list2)

## 出力結果
[0, 1]
[2, 1]
```

Numpyでスライスを用いると同じオブジェクトを”参照”する
（a1 = aの挙動）

```Python
np_array1 = np.array([0,1])
np_array2 = np_array1[:]
np_array2[0] = 2
print(np_array1)
print(np_array2)

## 出力結果
[2 1]
[2 1]
```



おわり
大学生が卒業旅行のためにWebアプリを２週間でリリースした話.その２

# はじめに
こんにちは。こちらはタイトルの通り、初心者大学生によるWebアプリ開発の話です。これは第二弾なので第一弾を読んでいない方は[その１](https://qiita.com/soutaginta/items/bf2b91d1e2f3f015efba)から読んでみてください！

第一弾では、アプリ開発の動機やアプリの概要について書きました。
第二弾では、**アプリの機能紹介と、Google AdSenseに広告申請した結果**をお伝えしたいと思います。

# アプリ概要おさらい
開発したアプリは「[**みんなで割り勘**](https://groupwarikan.com/)」です。
旅行など、**誰かがまとめてグループ全員の分を支払うことが多いときに役に立つアプリ**です。
支払いを記録しておくことで、解散するときに精算額を確認することができます。

オイオイ、こんな割り勘するだけのWebアプリなら他にも知ってるし今更遅いんだヨォ！と思ったそこのあなた。
これから**みんなで割り勘**だからこその機能を紹介していきますよ！！

:::note warn
旅行など、支払いが発生するたびにアプリを利用していただくことを想定しているため、スマホに合わせたUIになっています。
:::

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672991/4bd790c3-2a31-e134-928b-534d7d8324e3.png">

# 広告申請の結果やいかに！？
さて、前回の記事をあげた時点ではGoogle AdSenseに広告申請中でした。その結果が返ってきました！
結果やいかに！！　
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672991/c34f7a81-1ae7-da26-5e1f-1a9333429f79.png)

だめでした（涙目）
Google AdSenseは広告の審査が厳しめとは聞いていましたが、悔しい！
挑戦1回目はだめだったということでもっといいコンテンツになるよう改善するのみです。
広告が掲載されるのがいつになるかわかりませんが、1日でも早く承認されるよう全力で開発していきます。

# アプリの機能紹介
このアプリは、前回も書きましたが複数人で旅行やお出かけの際に真価を発揮します。
使い方は「[**みんなで割り勘**](https://groupwarikan.com/)」に実際にアクセスしてみてください！
使い方ページも設置したためそこだけでも確認していただけるとこの後に書くアプリの機能についてイメージしやすいと思います。

**激アツ機能.1**
実際に身の回りの人たちにこのアプリを紹介した際、いちいち過去に作ったグループ名なんて覚えてられないと言われたため、過去のグループが画面下部に出てくるようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672991/b81f1dfa-8c76-56f3-cf4a-46fb9e7119c2.png)

**激アツ機能.2**
作成したグループのみんなにリンクを共有することで、誰でも支払い履歴を記録できます。

**激アツ機能.3**
外貨対応！また、何の支払いかメモできます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672991/4cecdbf2-9b50-4d02-bd3d-1c2065827b78.png)

**激アツ機能.4**
**「支払い提案機能」**
アプリを作る上でいろんな割り勘アプリを見てきましたが、この機能は今まで見たことがありません。どんな機能かというと、次に支払いをする金額を入力することで、最後の精算回数を減らすことができます！
まだわかりにくいかと思いますが、簡単にいうと今までの支払い履歴から、最後の支払いが楽になるような払い手を提案してくれます！

とまあこんな感じですかね。また、使い方がわからなくなった時のために使い方ページにいつでも飛べるよう「？ボタン」が右上に設置されているのも優しいところです。ユーザーに寄り添った使いやすいアプリを目指しています。

# ではまた
一通り伝えたいことは伝えたつもりなのでこれからは広告が承認されたかや、新しい機能を追加したとき、製作中大変だったことなど気が向いたら書いてみようと思います。

ちなみに、共同制作者のM君も記事を書いてみたそうなのでぜひみてあげてください。↓

https://qiita.com/mrmmm0128/items/53901627029af0395e15

あと、Xも稼働しています。今はこのアプリを広めるためにできることはなんでも試してみている段階です。
応援してくださる方いましたらぜひXのフォローや記事のいいね、実際にアプリを利用してみるなどお願いします。

Xアカウント:

https://twitter.com/groupwarikan
Javascriptのブロック構文で引っかかった件について

JavaScriptで絞り込み検索機能を実装していたら、全然機能せず、四苦八苦していると超初歩的なミスに気がつきました。。。
今後のミス防止のためにも記録に残しておこうと思います！(ただの自己満笑)

## 問題です。どちらのコードが動作するでしょうか？
**パターン①↓**
```js:javascript
const filterWord = filterInputItem.value;
const filterSearch = articleList.filter(
  (article) =>
    article.name.includes(filterWord) || article.person.includes(filterWord)
);
```

**パターン②↓**
```js:javascript
const filterWord = filterInputItem.value;
const filterSearch = articleList.filter((article) => {
  article.name.includes(filterWord) || article.person.includes(filterWord);
});
```

## 答え

答えは**パターン①**です！
まあ、こうやって見ると分かりますよね、、、
パターン②の場合だと**ブロック構文**を使用しているので**return**を入れないとダメですよね！

## アロー関数と{}の使い方

#### {} なしのアロー関数 (暗黙の返り値)

```js:javascript
const add = (a, b) => a + b; // 戻り値は a + b
```

#### {} ありのアロー関数 (明示的な返り値)
```js:javascript
const add = (a, b) => {
  return a + b; // return が必要
};
```

## まとめ
**{} を使う場合**
・return が必要
・複数行書くときに使う。

**{} を使わない場合**
・return 不要
・一行じゃないとダメ

プログラミングってムズイよね。
LeetCodeを1日1題解いてみる (day18)

18日目に取り組んだ問題はこちら！

# 101. Symmetric Tree

https://leetcode.com/problems/symmetric-tree/description/

## 問題文
Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).

## 僕の回答 (失敗作)
```py
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        here = root
        stack = [[]]
        l, rt = here.left, here.right

        if l.val != r.val:
            return False
            
        while stock:
```

## GPTの回答
```py
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        stack = [(root.left, root.right)]

        while stack:
            left, right = stack.pop()
            
            if not left and not right:
                continue
            
            if not left or not right or left.val != right.val:
                return False
            
            # 左の左と右の右、左の右と右の左をペアでスタックに追加
            stack.append((left.left, right.right))
            stack.append((left.right, right.left))
        
        return True
```

## より効率の良い回答例
特にありませんでした。

### コメント
```py
stack.append((left.left, right.right))
stack.append((left.right, right.left))
```
ここの部分を思いつくことができなかった。

### 次の問題はこちら!
https://qiita.com/h_y_s_d/items/5db7f0c46c35f5662740
JavaScript: download系

`URL.createObjectURL`と`URL.revokeObjectURL`を組み合わせたdownloadの成功例と失敗例

## 自動
```js:成功
let a=document.createElement("a");
a.download="a";
a.href=URL.createObjectURL(new Blob(["text"]));
a.click();
URL.revokeObjectURL(a.href)
```
```js:失敗
let a=document.createElement("a");
a.download="a";
a.click(URL.revokeObjectURL(a.href=URL.createObjectURL(new Blob(["text"]))))
```
```js:成功
let a=document.createElement("a");
URL.revokeObjectURL(a.href=URL.createObjectURL(new Blob(["text"])),a.click(a.download="a"))
//2回目は失敗
a.click()
```
## 手動
```html:失敗
<a id=a download>DL</a><script>
a.onclick=()=>{
	a.href=URL.createObjectURL(new Blob(["text"]));
	URL.revokeObjectURL(a.href)
}
</script>
```
```html:失敗
<a id=a download>DL</a><script>
a.onclick=()=>URL.revokeObjectURL(a.href=URL.createObjectURL(new Blob(["text"])))
</script>
```
生成AI対策のノイズ意味無いと言われているから試してみた

:::note warn
ご注意
これは中立の立場での実験です
他人への強制や攻撃はおやめください
:::
# はじめに
SNSでたびたび論争になるので、気になったので試してみることに。
試したノイズは以下の2種類です
- Glaze 2.1
- Mist v2

使った画像生成AIは**Stable Diffusion WebUI Forge**です
https://github.com/lllyasviel/stable-diffusion-webui-forge

# i2i
まずは自作のイラストにそれぞれノイズをかけます
| オリジナル | Glaze | Mist |
|:-:|:-:|:-:|
|![s-i2i-test.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/b511f155-d769-32f9-244b-d54641b44352.jpeg) | ![s-i2i-test-Glaze.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/5d5976db-a009-0eb0-37be-edbc4c8a6a47.jpeg)|   ![s-i2i-testm-mist.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/62715f8e-fa10-6e54-1b14-f24c81911f2f.jpeg)|

i2iしてみましょう。謳い文句通りなら顔や体の認識ができなくなって破綻したりするはず…
| ノーガード | Glaze | Mist |
|:-:|:-:|:-:|
|![ノーガード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/e6038480-c8f5-32f0-0baa-bc82267f68d3.jpeg)|![s-00051-1716119739.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/e275f4db-100c-de67-cff7-4f8dcbe1019e.jpeg)| ![s-00060-2324289318.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/0fba1fb7-2e46-de5e-df86-eade5e134ba6.jpeg)|

ノイズが出ているものの破綻することはありませんでした。
期待している効果は出なかったものの、顔以外の部分はノイズが結構乗っています。
ノーガードと比較するとどちらも作品の見栄えに影響しているので修正がいるでしょう。
楽して絵描きから盗作したり、無断添削など出来なくなるので全く効果なしとは言い切れなさそうです。

# Lora
オリジナルキャラクターのイラスト15枚を使ってloraの作成をしてみます
Stable Diffusion WebUIの拡張機能「TrainTrain」を使っています
https://github.com/hako-mikan/sd-webui-traintrain

## 結果
| ノーガード |  |
|:-:|:-:|
|![s-ノーガード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/84dfc6f2-6bf3-6a51-aa9b-28e5fcbaa8cc.jpeg)|![s-ノーガード2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/f7244662-c0c3-3cad-0a9e-cc1efafbfe02.jpeg)|

影の書き方や目の描き込み、唇の画風などが模倣されました
　
| Glaze |  |
|:-:|:-:|
|![s-00063-11166837.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/38c67b3c-f2e3-399b-a509-bdb79768f492.jpeg)|![s-00017-2485410400.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/a26b5f09-9a1b-42f1-31aa-f1e6a2561040.jpeg)|

こちらもノーガード同様、影の書き方や唇の画風などが模倣されてしまいました
　
 | Mist |  |
|:-:|:-:|
|![s-00095-3015914035.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/d12a11db-5b0b-d4e2-cc21-97394bbb4cba.jpeg)|![s-00088-2903570017.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/b36a7417-ab8b-9555-55be-657a6e1c7352.jpeg)|

Mistを使っても模倣されてしまいました
ノイズが乗っているため修正は必要そうですが…
　
## ということで
GlazeとMist、両方ともかけてみたいと思います
| 重ね掛け |  |
|:-:|:-:|
|![s-00141-3274477097.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/1c7d556c-0f07-6d32-c61c-0c5f75b54e1a.jpeg)|![s-00120-760768260.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679188/43406280-dd11-41ae-4417-de76d1d7ee80.jpeg)|

両方かけることで細部の描きこみ(唇など)模倣しなくなりました
さすがに雰囲気や影の書き方は真似してきますが…

# 結論
完全に防げるというものではないことが分かりました
しかし、特徴的なノイズが乗ってしまうので、生成AI製だとはっきり分かる画像が出てくるようになります。
特にMistのノイズが強いですね。
修正が必要になるため、抑止力にはなるかもしれない？という結果になりました
楽してキレイな画像が欲しい方は避けるんじゃないでしょうか
エラー（解決済み）（備忘録）ubuntu(Mysql2::Error::ConnectionError ・ Can't connect to local MySQL server through socket '/tmp/mysql.sock')

## はじめに
題名のエラーが出たので「あーまたMysql動いてないのかー」という事でターミナルに
```
mysql.server restart
```
を打ちました。いつもなら動くのに今回は
```
The server quit without updating PID file
```
の表示。
色々調べるとMysqlをアンインストールして再インストールしないといけないようで
以下ご教授いただいたので残させてください。
ubuntu特有のコマンドだそうです。
以下をまとめて実行、PW求められたら入力。
```
sudo systemctl stop mysql ;
brew uninstall mysql@8.0 ;

sudo rm -rf /etc/mysql;
sudo rm -rf /home/linuxbrew/.linuxbrew/etc/my.cnf ;
sudo rm -rf /home/linuxbrew/.linuxbrew/var/mysql/ ;
sudo rm -rf /home/linuxbrew/.linuxbrew/var/log/mysql/ ;

sed -i '/export PATH="\/home\/linuxbrew\/.linuxbrew\/opt\/mysql@8.0\/bin:$PATH"/d' ~/.profile ;

source ~/.profile ;

brew install mysql@8.0 ;

echo 'export PATH="/home/linuxbrew/.linuxbrew/opt/mysql@8.0/bin:$PATH"' >> ~/.profile ;
```
ここでconfファイルが開かれるので以下記述があるか確認。
```
[boot]
systemd=true
```
確認できたら、ctrl + O → Enter → ctrl + X の順に押下して設定画面を終了し
以下を実行してUbuntuを終了する。
```
wsl.exe -t Ubuntu 
```
またubuntuを起動し、以下まとめて実行
```
brew services start mysql@8.0 ;
mysql.server start ;
mysql.server status ;
```
SUCCESSと表示されればmysqlの再インストールは成功。
その後はDBが無い状態になるので、create及びmigrateが必要になる。
## おわりに
最後の最後までお世話になり有難う御座いました!!!
gnuplotを利用してcsvからグラフ画像をささっと作る

実験系学者、学生の強い味方gnuplotの覚え書き。

python導入面倒だしcolab遅いから嫌だな～という人はぜひ検討を。
# 本編
1. ~.pltファイルを作成。拡張子はtxtとかでもOK
1. gnuplotに.pltファイルを読み込ませる
    - ターミナル上で`gnuplot hogehoge.plt`とか入力すると読み込める。
    - guiならFile->Openとかでいけるはず
# 解説なし版
```python
set terminal pngcairo enhanced font "Times New Roman,18" size 800,600
set grid
set datafile separator ","

set xlabel "X-axis"
set ylabel "Y-axis"
set title "Title"
unset key

set output "output.png"

plot "input.csv"  skip 1 using 1:2 with line linecolor 0
```
## 解説
```python
# hogehoge.plt

# pngと指定するとガビガビ画像になるのでpingcairoと指定して高画質にする。
# ほかの画像形式にしたい場合はpingcairoからjpegやepsとしておけばOK
# enhanced font "Times New Roman,18" はギリシャ文字まで含めてfontとfontsizeを設定してる
# 画像サイズ800x600
set terminal pngcairo enhanced font "Times New Roman,18" size 800,600 

# 補助線つける
set grid 

# csvは,で区切るので指定。
# 指定しないとdat形式（空白で区切るやつ）と勘違いしてエラー起こす
set datafile separator ","


set xlabel "X-axis" # x軸名
set ylabel "Y-axis" # y軸名
set title "Title"   # タイトル

# ファイル名を指定すると凡例にファイル名が表示されて厄介なので削除する
unset key

# 出力ファイル名。
# ここでepsやjpgにしても無視される
# 変えたいなら上にある　terminal　pngcairo の文章を弄ること
set output "output.png"

# 入力ファイル指定しプロット。
#一行目が各列の説明の場合skipで飛ばせる。２行３行となるなら1ではなく2や3にしよう。
# usingでどの列を使用するのか指定する。
# システムの都合で行末に,があった場合エラー起こすのであえてusing 1:2を入れている。
# 複数列ある場合は using 1:5 とかやれば指定できる。
# with line で線描画。ないと点描画する。データの並び順で線を繋ぐ
# linecolor 0 は黒色。ほかの色は本記事後述。
plot "input.csv"  skip 1 using 1:2 with line linecolor 0
```

# 対数表記、データの加工、ラベルの数式表記
```python
# 両対数表記。片対数にしたい場合はlogscale xあるいはlogscale y
set logscale

# データの加工。
# それぞれの列の値を変更したいときに。
plot "input.csv"  skip 1 using ($1-25):($2*1e6) 

# ラベルにギリシャ文字や数式を使いたいとき
set xlabel "{/Symbol w}_c^2"
# 添え字が離れたくない場合
set xlabel "{/Symbol w}@_c^2"
```
# 線の太さ、形式、色を変えたい
次のページに詳しく記載されている
https://atatat.hatenablog.com/entry/2020/07/26/090000
# gnuplotを導入するには
## windowsユーザー
[ソースフォージ](https://sourceforge.net/projects/gnuplot/files/gnuplot/)で公開されている
参考: [gnuplot公式ページ](http://www.gnuplot.info/download.html)
## Ubuntu等
`sudo apt install gnuplot`でOK


# メリット
- win,mac,linuxなどなど対応の幅が広い
- オープンソース
- 数式表記対応
- 軽い、速い
- excelからの脱却
- eps方式も対応。latexユーザーもニッコリ

# デメリット
- ドキュメントが少ない
- vscode等エディタでシンタックス対応してない（文字に色がつかないのでわかりにくい）
- 記法が何通りかあって記事ごとに違うものが紹介されていて混乱する
- 記事によってはlinuxじゃないとできないような手法も紹介されていてつらい

# さいごに
gnuplotは数式を出力させたり、線を複数本書き込めたり、なんならフィッティングまで対応していていろいろできるいいやつなんですがいかんせん書き方を忘れる......
Open3D の PointCloud から座標データをとりだす

https://qiita.com/567000/items/094989222854ba5ae951
これの続きです。
もう少しキャッキャッするために調べたことを……。

## open3d.geometry.PointCloud とは？

```python
pcd = o3d.io.read_point_cloud("data.xyz")
```

読み込んだ `pcd` は `open3d.geometry.PointCloud` 型です。
この型から座標を取り出す方法です。
（マニュアルみたら一瞬で解決することなのですが自分用のメモです）

### 点群を配列（Numpy）としてとりだせる

`np.asarray(pcd.points)` これで取り出して Numpy で遊べます。

```py
xyz = np.asarray(pcd.points)
print(xyz)
print(xyz[0])
print(xyz[0][0])
```

これで普通に配列として扱えるので何でも出来るようになります！

```text
# xyz
[[-22.755951   6.552761 -22.308571]
 ...
 [ 15.542783  -4.47567  -15.237212]]

# xyz[0]
[-22.755951   6.552761 -22.308571]

# xyz[0][0]
-22.755951
```

### 逆に Numpy を PointCloud にも出来る

```py
new_pcd = o3d.geometry.PointCloud() 
new_pcd.points = o3d.utility.Vector3dVector(data)
```

### 読み込んだ PointCloud を Numpy で加工してまた PointCloud に戻す

普通にデータを読み込んで表示するとこうなところを、、、

```py
import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("vase.xyz")
o3d.visualization.draw_geometries([pcd])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/c886b2f8-f603-7ff5-9b15-2206b8001677.png)

データを１つ１つ見て例えばある範囲内だけのデータをとりだして表示する（切り出す）なんてこともできます。

```py
import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("vase.xyz")

xyz = np.asarray(pcd.points)

data = np.empty((0,3))
for l in xyz:
    x =  l[0]
    y =  l[1]
    z =  l[2]
    if( 0.3>y and y>0.2 ):
        data = np.append(data, np.array([[x,y,z]]), axis=0)

new_pcd = o3d.geometry.PointCloud() 
new_pcd.points = o3d.utility.Vector3dVector(data)

o3d.visualization.draw_geometries([new_pcd])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/7b4b8405-5a3d-2a87-bb3c-4c8a9d7b2b94.png)

これが出来ることで、ノイズ除去とか、ダウンサンプリングとか、Voxel化とか、いろいろできますね！！
（ほとんど PointCloud の標準メソッドにも用意されていますが……自分好みで何かしたいこともあると思うので……）
Goで入出力

### 概要

Go言語で、キーボードから文字の入力を受け付ける処理について

### 実行結果

次の日のテレワークのおやつを入力するプログラム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3926100/19870e19-4906-5ebf-4c9b-dcf393a662ee.png)

### ソースコード

```
package main

import "fmt"

func main() {
	var input string
	for {
		fmt.Print("明日のテレワークおやつは何ですか。qキーで終了します：")
		fmt.Scanln(&input)

		if input == "q" {
			break
		}
		fmt.Println(input, "が入力されました")
	}
}
```

fmtパッケージのScanln関数を利用すると、キーボードからの入力を受け付けることができる
AIロボット入門のサンプルコードを動かす

「ROS2とPythonで作って学ぶAIロボット入門」という書籍を購入したので、サンプルコードを動作させるための環境 (@ Windows11) を構築。

https://amzn.to/4eFlueS

まずは以下のウェブサイトに従ってDockerのインストール。

https://docs.docker.com/desktop/setup/install/windows-install/

`Docker Desktop for Windows - x86_64`をダウンロードし、インストール。特に設定は変えずにデフォルトのまま。

次に、以下のサイトからrun.batをダウンロードし、実行。

https://github.com/AI-Robot-Book/chapter1/tree/main/docker#windows%E3%81%AE%E5%A0%B4%E5%90%88

ブラウザで`http://127.0.0.1:6080`にアクセスしたらデスクトップが表示された。

次に 

`export TURTLEBOT3_MODEL=waffle_pi`
`ros2 launch turtlebot3_gazebo empty_world.launch.py`

を実行するとGazeboが起動。

次に、Dockerを使わずにWindows11のWSLにインストールしているROS2 Humbleでも同様のことを実施。まずは
`sudo apt install ros-humble-turtlebot3-gazebo`
を実行したあと、上記でGazeboが起動。

しかし、以下のエラーメッセージが出ており、いくつかネットで調べた解決方法を試してみたが解決せず、Gazeboは断念。
`[Err] [World.cc:1803] World[test_world] is attempting to load a plugin, but detected an incorrect plugin type. Plugin filename[libgazebo_ros_factory.so] name[gazebo_ros_factory]`
メソッドがたくさんあることはいいことなのか？

# はじめに

記事の投稿数も 20 を超えたということで、ポエムでも書いてみようと思います。

コードを書いていて、自分がよく知らないクラスを使うときにとりあえず `.` を入力してクラスのメンバの一覧を表示することがあります。このとき候補にたくさんのメンバーが表示されると少しだけうんざりした気持ちになります。  
要はひとつのクラスに詰め込みすぎるとひとつひとつの機能が見えにくくなりますよ、というお話です。

:::note info
今回はあくまで筆者が日頃そう感じる、程度の内容です。フレームワークや言語設計に注文をつけているわけではありません。
:::

## 具体例

上の例では単一責務の原則 <https://ja.wikipedia.org/wiki/%E5%8D%98%E4%B8%80%E8%B2%AC%E4%BB%BB%E3%81%AE%E5%8E%9F%E5%89%87> に倣えば実際は起こりにくいです。  
一方でやむなく巨大クラスになる場合はしばしば起こり得ます。[System.Windows.Forms.Control](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control?view=windowsdesktop-8.0) のような、深く継承を使った例では小さなクラスにまとめるのは難しいでしょう。

今回はより身近な例として、[System.Collections.Generic.IEnumerable\<T>](https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.generic.ienumerable-1?view=net-8.0) の**拡張メソッド群**について取り上げてみます。

## `IEnumerable<T>` 拡張メソッド群

拡張メソッドは C# 3.0 に導入されました <https://ufcpp.net/study/csharp/sp3_extension.html>。同じタイミングで LINQ <https://ufcpp.net/study/csharp/sp3_linq.html> も導入されました。LINQ 機能を実現する上で拡張メソッドが有用だった、という背景です。

C# 13.0 /.net9.0 時点でこの `IEnumerable<T>` には **79 個**もの拡張メソッドが定義されています（オーバーロードを含めると 199 個）。`.` を入力してクラスのメンバーの一覧を出したらスクロールバーが小さすぎて笑えたのは誰しもが通る道でしょう。

自分はそのクラスにどんなメンバーがあるか、上から候補を確認する**舐める**作業をよくやるのですが、メンバーの数が多いとこの作業をやる気が起きなくなります。拡張メソッドによってメンバーが埋もれている場合も同様です。  
また、拡張メソッドの**オーバーロード**が大量にある場合も、パッと見どれが適切なのかわかりにくい問題があります。オーバーロードなので基本的にはどれが呼ばれても問題はないのですが、オプションを渡して機能を調整する系のオーバーロードは見落としたくないところです。クラス本体のメソッドシグネチャとバッティングした場合**クラス本体のメソッドが優先される**わけですが、コードを見ただけでは分かりづらくエディタの該当メソッドにマウスカーソルを当ててどのメソッドか確認する作業を強いられます。オーバーロードに関してはジェネリック、オプション引数、可変長引数、特殊なパターンなどで複雑になりがちです。

`IEnumerable<T>` 拡張メソッド群の本体は [`System.Linq.Enumerable`](https://learn.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable?view=net-8.0) で、ここに大量の拡張メソッドが定義されています。`IEnumerable<T>` とは別に定義されているので、候補がノイズに感じるときは非表示にする方法はあります。  
拡張メソッド本体のクラスを、現在のコードから見えないように名前空間を未参照にします。

```cs
// using System.Linq;
```

ただ、最近は C# プロジェクト単位で `global using` していることもあるので、この方法は使えないこともあります。

```text
<!-- <ImplicitUsings>enable</ImplicitUsings> -->
```

## 拡張メソッドに関するあれこれ

- 継承できない型（`sealed`、値型、列挙型）にメソッドを付け足せるので便利な機能
- `public` にすると影響が大きいので `internal` にして気軽に使う
- インターフェイスに関してはデフォルト実装 <https://ufcpp.net/study/csharp/cheatsheet/ap_ver8/#default-imeplementation-of-interface> という選択肢もある
- 本来はインターフェイスの型を使うユーティリティ型のメソッドにするべきだが、そうすると**存在を忘れるため、目立たせるために拡張メソッドにする**使い方を稀にする

## おわりに

個人的にはクラスは小さいほうが扱いやすくて好みで、メンバーは少ないほうがクラスを把握しやすいです。  
今回は `IEnumerable<T>` の例を出しましたが、これは歴史的な理由もあってこうなっているので仕方のないところでもあります。  
突き詰めるとアセンブリは小さいほうがいい、アプリは小さいほうがいいみたいな話になりそうですが、それは別の機会にでも。

自分はマネージャクラスにあれこれ詰め込んで肥大化させる癖があるので、適切にリファクタしてクラスを小さく保ったほうがいい、という自戒を含めたお話でした。
【Unity】オブジェクトの中心座標の取り方

:::note info
これできるの初めて知った
Markdown便利ね～
:::
というのは置いといて中心座標の取り方です。

```c#
  // ブロックの中心座標 
  Vector3 BlockCenter()
  {
      // カメラからマウスへrayをとばす
      Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
      RaycastHit hit;
      Renderer renderer;
      // 未割当でエラーになるためzero入れている
      Vector3 center = Vector3.zero;
      
      if (Physics.Raycast(ray, out hit))
      {
          renderer = hit.transform.GetComponent<Renderer>();
          // オブジェクトの範囲の中心
          if (renderer != null) center = renderer.bounds.center;
      }
      return center;
  }
```
自作PCにてWindowsインストール途中でフリーズした話

# 概要
自作PCにWindowsをインストールする際、Windowsアップデートした後、フリーズする現象に悩みました。
改善方法を共有します。

# 環境
マザーボード: TUF GAMING B650-E WIFI
CPU: AMD  Ryzen 5 9600X BOX
GPU: 玄人志向  GG-RTX4070-E12GB/DF2 (GeForce RTX 4070 12GB)
メモリ: Crucial  CT2K16G56C46U5 (DDR5 PC5-44800 16GB 2枚組)
ストレージ: KIOXIA  SSD-CK1.0N4PLG3J (M.2 2280 1TB)

# 問題
上記の構成のPCにUSBに、作成したインストールメディアを使ってWindowsをインストールしようとしました。
Windows設定の途中までいくものの、設定途中のWindowsアップデート後の再起動時、フリーズする現象に悩まされました。

# 考えた解決法
1: オフラインでWindows設定を行う。
2: Windows設定画面が出てきたら、刺していたUSBを抜く。

# 結論
上記2の方法で解決しました。
これは推測ですが、Windowsアップデートした後に再起動する際、バグか何かでUSBに保存されたWindowsインストールブースターがBIOSで起動されてしまっていたのではないかと思います。結果、Windowsがインストールされているのに、インストールブースターが起動されてしまいフリーズしていたと想定します。

上記1の方法は試していませんが、オフラインでWindowsを設定すれば（例えばこれが参考になります https://note.com/ictlink/n/n1092116ee9ba ）、Windows設定中にアップデートが入らないのでフリーズを回避できたかもしれません。試していないので、分かりませんが。
Windows11にWSLとROS2をインストールした時のメモ


# 環境
- Windows11
- WSL2
- Unbuntu 22.04

# 作業手順
以下を参照
https://wisenetwork.net/archives/4739

Ubuntu 22.04をdefaultにするためにPowerShell上で以下を実行
`wsl --set-default-version 2`

次にubuntu-desktopをインストールする。上記をサイトを参照しているが、少し修正し、以下の順に実行する：
`sudo apt-get install libgl1-mesa-dev xorg-dev xbitmaps x11-apps`
`sudo apt-mark hold acpid acpi-support`
`sudo apt-get install ubuntu-desktop`

# ROS2 のインストール

以下を参照：
https://docs.ros.org/en/foxy/Installation/Ubuntu-Install-Debians.html

ただし、Ubuntu 22.04はFoxyをサポートしていないので、以下を実行し Humbleをインストール：
`sudo apt install ros-humble-desktop python3-argcomplete`

もともとの目的はGazeboを動かすことだったが、起動はするもののエラーを出して正しく動作してしなかったので、Ubuntuははアンインストールした。
【C# 12】適切なメール送信方法について

# はじめに

メールを送る際に、System.Net.Mailが非推奨となっていた。
そのため、代替案を調査した。

## 前提
### 環境
.NET 8.0
C# 12.0
MailKit 4.7.1.1
Outlook 2016

# 代替案

結論から申し上げると、MailKitをおすすめする。
OutlookをC#から操作する方法を使用した場合、メールを送信せず、Outlookが勝手に終了することがあるためである。

## MailKit

OutlookをC#から操作する方法に比べ面倒が少ないため、MailKitをおすすめする。
また、Microsoftの公式ドキュメントに「MailKit」を名指しで書いているだけあり、ネットで検索した際に情報量が多いというメリットもある。

### サンプルコード

[@ITの「テキストメールを送信するには？」](https://atmarkit.itmedia.co.jp/ait/articles/1811/21/news023.html)を参照すること。
記事は古いが、.NET 8.0のC#でも動作した。

## Outlook(COMオブジェクト)

セットアップ済みのOutlookさえあれば、動作可能な点がメリットである。
一方で下記デメリットが存在する。
- Outlookのインストール・セットアップが必要であること。
- Outlook起動中に、C#からOutlookを操作し、メールを送信しようとすると、メッセージボックスが表示されてしまう。
※ メッセージボックスにて、何も選択しない場合は、メールを送信せずに終了する。

### 表示されるメッセージボックス

![outlook.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3663791/4877a7d8-11b9-1486-53c8-40ee507b8ccc.png)

### サンプルコード

``` C#
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Runtime.InteropServices;

namespace Sample
{
    class Program
    {
        static void Main(string[] args)
        {
            var outlook = new Outlook.Application();
            try
            {
                Outlook.MailItem mail = outlook.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem;
                Outlook.AddressEntry currentUser = outlook.Session.CurrentUser.AddressEntry;
                mail.Body = "hoge";
                mail.Recipients.Add("hoge@hoge.com");
                mail.Recipients.ResolveAll();
                mail.Send();
            }
            finally
            {
                outlook.Quit();
                Marshal.ReleaseComObject(outlook);
            }
        }
    }
}
```

#### 注意事項

下記DLLの参照設定が必要である。
Microsoft.Office.Interop.Outlook.dll

## さいごに

「System.Net.Mail」の代替案を調査した結果、「MailKit」をおすすめする。

### 参考文献

https://qiita.com/vicugna-pacos/items/b0f94c590f018c7e0d16

https://qiita.com/minoura_a/items/7847772bbbcb7cbfddd4

https://qiita.com/SKY-HaYaTo/items/cfdf706a9b735c2ac01a

https://atmarkit.itmedia.co.jp/ait/articles/1811/21/news023.html

https://elleneast.com/?p=10085

https://github.com/dotnet/platform-compat/blob/master/docs/DE0005.md

https://learn.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.marshal?view=net-8.0

https://www.infoq.com/jp/news/2017/04/MailKit-MimeKit-Official/

https://marunaka-blog.com/csharp-mail-send-mailkit/10081/

https://learn.microsoft.com/ja-jp/dotnet/api/system.net.mail.smtpclient?view=net-8.0
CCIE受験しました　2回目

先日、CCIE Enterprise Infrastructureのラボ試験(2回目)を受験しました。
結果は100点満点中...20点くらい?でした。ですが、各セクション0%は回避できたので少し成長したと思いたいです。

##
#### 感想
似たような問題もありましたが、前回すんなりconfigを設定できた問題がトラブルシュートになっていたりと、まったく同じ問題は少なかったように思います。
前回よりは落ち着いていたものの普段通りとはいかなかったです。些細な仕掛けにも気づけずに時間を無駄に費やした箇所がいくつかありました。
時間がなくなってくると焦って、落ち着いて考えれば分かりそうな問題も後回しにしてしまいました。いかにスムーズに基本設定を完了させて時間と心に余裕を持たせるかが課題だと感じました。

今回変えてよかったなと思うことは、画面のレイアウトです。
前回の試験で全体をふわっと(かっこいい言葉でいうと俯瞰して)考えることを求められている気がしたので、全体の構成図と詳細な構成図を常に表示していました。前回は必要な時に出していたので、画面がごちゃごちゃになってしまうというロスもありました。
あと、terminalの機能も活用しました。複数装置をまとめて開くと画面が整理できるし、一括でコマンドをいれる機能を使うことでコピペ回数はかなり減った気がします。

それでも時間は足りないし合格までは程遠いので、あとはもう勉強するのみです。
年度内にもう一回ラボ予約とれるといいな。


##
前回以降やったことと、これからやることを書き残します。
#### やったこと
前回からの期間は約2か月です。
丁寧に勉強することと、英語の長文に慣れることを意識しました。
<br>

1.『End-to-End QoS Network Design: Quality of Service for Rich-Media & Cloud Networks (Networking Technology) 2nd Edition』

https://www.ciscopress.com/store/end-to-end-qos-network-design-quality-of-service-for-9780133116106

図が多めでわかりやすいです。
Chapter 11. QoS Design Principles and Strategiesがまとめのようになっていて、試験までに何回か読み返しました。ただ、前回ほど詳細まで問われなかったです..

<br>

2.『Optimal Routing Design』

https://www.ciscopress.com/store/optimal-routing-design-paperback-9781587142444

演習に重点をおいた本だと「R1にルート集約する設定をいれなさい」というように決められていることが多いですが、この本を読むと「なぜR1なのか」という理解が深まります。それぞれの技術のメリット・デメリットが説明されていて、文中の"advantage" "issue"という単語に印をつけながら読みました。

<br>

3.『CCIE Enterprise Infrastructure Foundation, 2nd Edition』

https://www.ciscopress.com/store/ccie-enterprise-infrastructure-foundation-9780137374243

演習問題集です。勉強をはじめたころからお世話になっていますが、いまだに発見があります。この本のおかげで引き出しの数はすごく増えました。正解できたところも解説を丁寧に読んで、疑問に思ったことを調べていく方法で勉強しなおしました。
<br>

4.『Cisco Software-Defined Wide Area Networks: Designing, Deploying and Securing Your Next Generation WAN with Cisco SD-WAN』

https://www.ciscopress.com/store/cisco-software-defined-wide-area-networks-designing-9780136533177

SD-WANについて体系的に理解したいなと思い購入しました。SD-WANのpolicyは種類がたくさんあってわかりづらいと感じていましたが、この本はそれぞれのpolicyについて丁寧に記載してくれています。Use Caseが豊富で、同じCaseでも複数パターンの設定が記載されているところが良いです。
<br>

##
#### やること
全体的に勉強しなおそうと思います。

・learning matrixを参照しながらCCOや書籍をひととおり確認
・『Cisco Software-Defined Access』読む

https://www.ciscopress.com/store/cisco-software-defined-access-9780136448389


##
#### おまけ
ラボ試験について、Enterprise Infrastructure受験者向けの公式動画がありました。
CCIE試験で求められることや採点基準、改定前との違い、画面操作などの動画です。
v1.0の説明のようですが、試験環境や求められることはv1.1も同じと思うので、受験前までに絶対見たほうがいいです。

CCIE Enterprise Infrastructure Training Videos

https://learningnetwork.cisco.com/s/learning-plan-detail-standard?ltui__urlRecordId=a1c3i0000015c1OAAQ&ltui__urlRedirect=learning-plan-detail-standard&t=1731830012620
Discordがクラッシュして突然開かなくなった

## 背景
タイトルの通りDiscordを開くと下記画面が表示され、開かなくなりました。
リロードを押しても変わらずです。
そのため、対処法について調べることにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3931306/3c4661ca-9394-c3fa-e75b-dad97e94ae76.png)

## キャッシュを削除する

下記記事に様々な原因が記載されていました。

https://recorder.easeus.com/jp/screen-recording-tips/discord-keeps-crashing.html

その中でキャッシュの削除が簡単でかつ効果がありそうだったので、記事を参考に下記手順でキャッシュを削除しました。

1. 「Windows+R」でファイル名を指定して実行ダイアログボックスを開き、`%appdata%/discord`を入力して実行する(アプリケーションフォルダの中にあるDiscordフォルダを開く)
1. `Cache`、`Code Cache`、`GPUCache`を削除する
    この時、ほかのプログラムがフォルダを開いていて削除できない旨の警告が出てきたので、タスクマネージャでDiscord関連のシステムを終了させました


上記手順後、Discordを再度開いたら無事普段の画面が出てきました！
上記手順の2において、他にもCacheフォルダはありましたが、とりあえず指定されていたCacheフォルダを削除しました。指定されていたCacheフォルダがよくクラッシュおこしやすいとかなのかなと思っています。


## おわりに
今回のクラッシュはキャッシュが原因のようでした。
解決が長引くかなと思い、記事作成と並行して作業しましたがすぐ解決できました。
やはりキャッシュは最初に疑うべきですね。
【速読】SREサイトリライアビリティエンジニアリングの全体像を掴む

# １．はじめに
オライリー・ジャパン発行オーム社の『[SRE イトリライアビリティエンジニアリング](https://www.amazon.co.jp/SRE-%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0-%E2%80%95Google%E3%81%AE%E4%BF%A1%E9%A0%BC%E6%80%A7%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%81%E3%83%BC%E3%83%A0-%E6%BE%A4%E7%94%B0-%E6%AD%A6%E7%94%B7/dp/4873117917 "SRE イトリライアビリティエンジニアリング")』という書籍があります。
こちらは高額かつ大変分厚い書籍です。

この記事は、私が勉強のため本の内容を簡潔にまとめたものです。
全体像を理解することに重点を置いているので、非常にざっくりとした説明になっています。
私の解釈も交えて記載しているので、もしかすると記載内容に疑問を覚える方も出てくるかもしれません。
詳細は、実際に書籍を読んであなたの目で確認してください。
読まなくても、世間話で通じる程度の知識が欲しい場合は、この記事の内容で十分だと思います。

# ２．書籍の概要
この本は、GoogleのSREチームの人が自分たちはこうやって開発＆運用しているよ、ということを説明した内容になっています。
本書でSREチームの目的は、Webサービスを稼働させること、そして最終的にはWebサービスの健全性に責任を持つことだと定義されています。

上記だけ聞くと、なんのこっちゃとなりますので、次項目で具体的な仕事内容について説明します。

# ３．SREエンジニアとは
IT業界の職種として、一般の人が思い浮かべるのはシステムエンジニアという名前でしょうが、システムエンジニアにも様々な職種があることは業界内の人なら知っていると思います。
非常に大まかなくくりなのですが、システムエンジニアを「開発」と「保守・運用」という二つのチームに分けた場合、SREは「開発」と「保守・運用」にまたがって活動する第三のチームとなります。
SREは「開発」の視点を持って「保守・運用」を効率化することが役割となります。

# ４．SREの仕事内容
では、SREチームは具体的にどんな仕事をするのでしょうか。
GoogleのSREチームは、次のような仕事に注力しているようです。
・システム監視（モニタリング）の設計、インシデント管理
・キャパシティプランニング、リソース管理
・プロビジョニング（ロードバランサ―の設定など）
・バックアップ、リストア設計
・リリースの設計
・ユーザーID登録などの運用作業自動化
などなど……お気づきの方もおられると思いますが、上記に述べた作業は、インフラエンジニアおよび運用エンジニアが実施していた仕事が含まれます。

企業によっては単純作業をする運用エンジニアと、設計をする開発エンジニアを分けていますが、イメージ的には運用エンジニアの上位に立って開発エンジニアと一緒に運用を設計をするのがSREの仕事となります。

最近は、SREエンジニアという職種が求人票に記載されるようになってきています。
しかしSREエンジニアに必要なキャリアというのは企業によって異なる上に、インフラエンジニアと開発エンジニア、半々の割合で応募されているようです。
インフラエンジニアであれば開発部署の仕事を理解していることが求められ、開発エンジニアであればインフラエンジニアの知識が要求されます。
さらに目的は「Webサイトの安定稼働」。シンプルですが奥深いのが、SREエンジニアという職種の仕事になります。

# ５．印象的だったこと
書籍を読む中で印象的に感じたのは、以下の文章でした。
・100%を信頼性の目標とすることは、基本的にいかなる場合にも間違っている
完璧を目指そうとするときりがなく、システム構築に掛かる費用（コスト）も増大します。
バランスを取ることが必要ですが、エンジニアではない社員が上役の場合、なんでもかんでも完璧に直せと言って困ることがあるので、現実にはなかなか難しいことです。
本文中には、メールアラートが大量に飛び過ぎて業務が過負荷になっていたところ、思い切ってメール通知を無効化したら調査する余裕ができたというような事例もありました。
権限があるなら是非とも周囲を説得して、無駄なメール通知を減らしたいものです。

・トイルは50%以下に抑える→SREは運用チームではない（少量の作業を楽しめるのであればトイルも悪ではない。問題は、運用ばかりでクリエイティブな改善ができないこと）
プログラミングが得意なエンジニアであれば、どんな作業も自動化してしかるべきだと考える方もいますが、四六時中設計しているのも疲れるものです。
私は単純作業も、片手間くらいならあって良いと思う人なので、Googleの人が上記のように言っているのを読んで気が楽になりました。

# ６．終わりに
書籍の内容を簡単に記載しましたが、いかがだったでしょうか。
あまり専門用語を使わず、平易な表現に直していますので、人によっては物足りないと思います。
私自身、このような記事を書くのは慣れていないので、甘口になっているのはご容赦ください。
また、SREの実践ができれば、具体的かつ専門的な内容で記事を書きたいと思います。
それではご拝読ありがとうございました！
test

```
#Set-ExecutionPolicy RemoteSigned -Scope Process
$ErrorActionPreference = "stop"
Set-PSDebug -Strict
#Set-PSDebug -off
Set-StrictMode -Version Latest

$rootPath="_"
$pattern = "*.log"

$OutputPath="_"




$has_Threads = @{}

function Fn_GetFileName([string]$FileName,[string]$ExtName){
    Get-Date -Format ("yyyyMMddHHmmss")
    return $FileName+"_"+(Get-Date -Format ("yyyyMMddHHmmss"))+"."+$ExtName
}



Function Rn_HashAdd($ThreadID){
    $ThreadID
    $has_Threads.Add($ThreadID,$null)
    
    $has_Threads[$ThreadID] =
        $has_DiffFiles = 
        @{
            DiffFileName =$null
            FetchStart_TS =$null
            FetchEnd_TS =$null
            WorkDelCount =$null
        }
}


$line = $null

#出力
function Fn_StreamOpen($InFile){
        $fs = [System.IO.File]::Open(
            $_,
            [System.IO.FileMode]::Open,
            [System.IO.FileAccess]::Read,
            [System.IO.FileShare]::ReadWrite + [System.IO.FileShare]::Delete
            
            )
        $sr = [System.IO.StreamReader]::new($fs,[System.Text.Encoding]::GetEncoding("sjis"))

        return $sr
}

#MainProc

#ファイル一覧生成
$InputFileList=@(robocopy $rootPath NULL $pattern /L /NP /FP /NS /NC /NJH /NJS /NDL )
#$InputFileList=@(robocopy $rootPath NULL $pattern /L /E /NP /FP /NS /NC /NJH /NJS /NDL ) #サブディレクトリあり
$InputFileList = $InputFileList -ne ""
$InputFileList = $InputFileList.trim()

#ファイルリスト全体を実行

#$sw = [System.IO.StreamWriter]::new($fs,$false,[System.Text.Encoding]::GetEncoding("sjis"))

$InputFileList | &{
    Process {$_
        #ファイルオープン
        $sr = Fn_StreamOpen($_)

        while (($line = $sr.ReadLine()) -ne $null) {
            #ログフォーマット
            $line    
            $lineReg = [regex]::Matches($line,"^\[(?<TimeStmp>[^\]\[]+)\]\t<(?<ThreadID>[^><]+)>\t(?<Comment>.*)$")
            if ($lineReg.count -ne 0){
                "Hit:"+$line
                $ThreadID = $lineReg[0].groups['ThreadID'].value
                Rn_HashAdd($ThreadID)
             }else
             {
                "not:"+$line
             }
        }

            
            #ログ分析
        
            ##スレッドレベル情報の取得
        
            ##ファイル毎情報の取得

    #ファイルクローズ
    $sr.Close() 
    $has_Threads
    }
}     

#スレッドの開始と終了


#スレッドｘファイル名の開始と終了
# +連続して表示される削除記号
#　スレッド番号内で順にログが出現しない場合はエラーとして空のまま出力し情報を捨てる

    



#Set-ExecutionPolicy RemoteSigned -Scope Process
$ErrorActionPreference = "stop"
[string]$ThreadID="Thread=1"

[string]$FileName1 = "F1.txt"
[string]$FileName2 = "F2.txt"

$Roop = @{}
$Roop.Add($ThreadID,@{
    ThreadStart = 1
    ThreadEnd = $null
    WorkDel = $null
})


$Roop.$ThreadID.Add($FileName1,@{
    FetchStart = 2
    FetchEnd = 3
})


$Roop.$ThreadID.Add($FileName2,@{
    FetchStart = 4
    FetchEnd = 5
})

$Roop.$ThreadID.ThreadEnd = 6
$Roop.$ThreadID.WorkDel = 100

$Roop.$ThreadID.Keys





<#

$Roop = @{
    $ThreadID = @{
        ThreadStart = 1
        ThreadEnd = 10
        WorkDelCount = 100
        $FileName1 =@{
            start = 2
            end = 3
        }
    }
}

$Roop.$ThreadID.$FileName1.start
$Roop.$ThreadID.$FileName1.end


#>
```
特定のゲームでマウスホイールのスクロールがほんの少ししか動かない問題を解決する方法

## 背景
日常操作では問題なかったがゲームでスクロールをすると全然動かず、不便だったため。また検索しても特に記事が見つからなかったため。

### 環境
windows11

### 解決方法

以下の手順で設定を変更。

```
設定画面を開く
「設定」 > 「Bluetoothとデバイス」 > 「マウス」の順に進みます。

スクロール量を変更
「マウスホイールでスクロールする量」を「複数行ずつ」に設定します。

```

### なぜこの問題が起こるのか？
考えられる原因

ゲームの解像度やユーザーインターフェース（UI）の設計によって、スクロール量が期待通りにならない場合があります。例えば、ゲーム内での「1画面」の定義が独自の基準に基づいている場合、システム側のスクロール設定とのズレが発生し、スクロール量が少なくなるのではないか。
Rails 8でもannotate_modelsのコメントを入れたい

## 結論
annotate_models のメンテナンスが滞っているため、 annotaterb に移管しよう。

https://github.com/drwl/annotaterb

## annotate gem とは
ActiveRecord を利用する際にファイル上部に db schema をコメントで自動追記してくれる gem になります。

```rb
# == Schema Info
#
# Table name: line_items
#
#  id                  :integer(11)    not null, primary key
#  quantity            :integer(11)    not null
#  product_id          :integer(11)    not null
#  unit_price          :float
#  order_id            :integer(11)
#

class LineItem < ActiveRecord::Base
  belongs_to :product
  . . .
```

Railsのバージョンをv7系からv8に上げようとするとannotate gemのバージョンがv3->v2になってしまいdiffが出る。
↓こちらでannotate_models v3系はActiveRecordのバージョンが7系以下である必要があり、v8に挙げたところでサポート外になってしまった。
そしてannotate_models v2.6.5がActiveRecordのサポートバージョンの上限が指定されていなかったため、Railsを挙げるとannotateが2.6.5になるという事件を起こしていた。。。

https://github.com/ctran/annotate_models/blob/5d01c4171990c4fe7b9b0977b05ce14a98209e53/annotate.gemspec#L26

(2024/11/17現在の話です)
Rails v8へのサポートに関してはissueもPRも上がっているが現時点で進捗なし。
annotate gem自体のアップデートが2023/11で止まっていました。

https://github.com/ctran/annotate_models/issues/1032#issuecomment-2465442708

## annotate_modelsからannotaterbに載せ替える
annotate_modelsからforkしたということもあり使用感などほぼ変わらず。

https://github.com/drwl/annotaterb

載せ替えのマイグレーションに関してはこちらのガイド通りに進めればOK

https://github.com/drwl/annotaterb/blob/main/MIGRATION_GUIDE.md

* Gemfileのannotateをannotaterbに書き換えてbundle install
* `bin/rails g annotate_rb:install` の実行

必要に応じて `.annotaterb.yml` を修正。
annotateの実行は `bundle exec annotaterb models`
初心者向け：AWS EC2インスタンスにEFSをマウントする手順とファイル作成・削除検証

## はじめに
Amazon Elastic File System（EFS）は、AWSが提供するスケーラブルなネットワークファイルシステムです。

:::note
**複数のEC2インスタンス間で共有可能で、クラウド上でデータの共有やバックアップを効率的に行うことができます。**
:::

本記事では、EFSをEC2インスタンスにマウントする手順を解説し、その後簡単な動作確認を行います。

## EFSとは
EFSはAWSのマネージドファイルストレージサービスで、次のような特徴があります。

![スクリーンショット 2024-11-17 20.12.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/b360f428-7a85-c0c0-04e7-19f081852d8c.png)
引用画像：https://recipe.kc-cloud.jp/archives/11974/

:::note warn
- **共有可能:** 
同じVPC内の複数のEC2インスタンスから同時にアクセス可能。

- **スケーラブル:** 
ストレージ容量が動的に拡張され、容量を気にせず利用可能。

- **高可用性:** 
複数のAZ（アベイラビリティゾーン）にまたがる冗長構成で設計されているため、高い耐障害性を提供。
:::

これにより、データの共有やバックアップ、分散アプリケーションのストレージとして最適です。

## 実際にやってみた
### 1. EFSの作成
AWSマネジメントコンソールで「EFS」サービスを開き、「ファイルシステムの作成」を選択します。

![スクリーンショット 2024-11-17 19.49.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/b0d2dbf2-6040-bafe-4665-a4d8a70be419.png)

使用するVPCを指定し、必要に応じてセキュリティグループを設定します（ポート2049を許可）。

![スクリーンショット 2024-11-17 20.01.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/eae5e6b0-ac4d-fa9e-9641-8d5183141d3e.png)

作成完了後、ファイルシステムID（例: ``fs-XXXXXXXX``）を確認しておきます。

![スクリーンショット 2024-11-17 19.51.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/3c2d7e71-44be-b48f-42ee-b56d7d452e70.png)

### 2. EC2インスタンスの準備

以下のコマンドを実行してEFS関連のユーティリティをインストールします。

```bash
sudo yum update -y
sudo yum install -y amazon-efs-utils
```

ここでは、インスタンスコネクトを使用して接続し、確認を行っています。

![スクリーンショット 2024-11-17 19.53.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/5c654169-f66d-8c0b-9c0e-f589c7c22ead.png)


次に、マウント先となるディレクトリを作成します。

```bash
sudo mkdir /mnt/efs
```

### 3. EFSのマウント

以下のコマンドでEFSをマウントします。``fs-XXXXXXXX`` は作成したEFSのIDに置き換えてください。

```bash
sudo mount -t efs -o tls fs-XXXXXXXX:/ /mnt/efs
```

次に、以下のコマンドでEFSが正常にマウントされているか確認します。

```bash
df -h
```

``grep``コマンドを組み合わせて結果を確認したところ、EFSが正常にマウントされていることが確認できました。

```bash
[ec2-user@ip-10-0-1-84 ~]$ df -h | grep efs
127.0.0.1:/     8.0E     0  8.0E   0% /mnt/efs
[ec2-user@ip-10-0-1-84 ~]$ 
```

さらに、自動マウントを有効にするために、``/etc/fstab``ファイルを編集します。

```bash
fs-XXXXXXXX:/ /mnt/efs efs defaults,_netdev 0 0
```

## 検証確認

EFSが正常に動作しているかを簡単な操作で確認します。以下のコマンドを実行して、マウント先にファイルを作成します。

```bash
echo "Hello EFS" | sudo tee /mnt/efs/hello.txt
```

作成したファイルが存在するか、以下のコマンドで確認します。

```bash
ls /mnt/efs
```

実際に、マウント先の``/mnt/efs``にファイルが作成されていることが確認できました！

![スクリーンショット 2024-11-17 20.04.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/6ad497bf-1c22-2c61-7922-43de91be7346.png)


不要になったファイルを削除する場合は、以下のコマンドを実行します。

```bash
sudo rm /mnt/efs/hello.txt
```

その後、再度``ls /mnt/efs``コマンドで確認し、ファイルが削除されていることを確認できました。

## まとめ

EFSを利用することで、複数のEC2インスタンス間で効率的かつスケーラブルなデータ共有が実現できます。

:::note
**今回、久しぶりにEFSをEC2にマウントする作業を行いましたが、意外とスムーズに進めることができました！**
:::

初学者向けの内容ですが、誰かの技術の支えになれば嬉しいです！

## 参考記事

https://dev.classmethod.jp/articles/ec2-efs-mount-for-beginner/

https://qiita.com/t-kigi/items/75921673e5e227ecc00f