OmniAICreator/Qiita-1.07M huggingface dataset:
[Django] ChannelsでRedisをバックエンドに設定するには？



Django Channelsでは、

WebSocketなどのリアルタイム機能を実装するために、
Redisをバックエンドとして使用することが一般的。

具体的には、
Channelsは「チャンネルレイヤー」という概念を導入しており、
これにより複数のconsumerインスタンスが互いに通信でき、
このチャンネルレイヤーのバックエンドとして使用できる。

### ChannelsでRedisをバックエンドに設定
Django ChannelsでRedisをバックエンドに設定する手順は以下の通りです。

#### 1. Redisのインストール
まず、ローカルにRedisをインストールするか、Dockerを使用してRedisを実行します。以下は、Dockerを使用してRedisを実行するコマンドの例です。

```python
docker run -p 6379:6379 --name my-redis -d redis
```

#### 2. Channelsとchannels-redisのインストール
次に、Django Channelsとchannels-redisをインストールします。channels-redisは、Redisをバックエンドとして使用するためのパッケージです。
```python
pip install channels channels-redis
```

#### 3. Djangoの設定
Djangoの設定ファイル（通常は settings.py）を開き、以下の設定を追加または変更します。

##### 3.1 INSTALLED_APPSにchannelsを追加
```python
INSTALLED_APPS = [
    # ...
    'channels',
    # ...
]
```
##### 3.2 CHANNEL_LAYERS設定を追加
```python
# settings.py

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],  # Redisのアドレスとポートを指定
        },
    },
}
```

##### 3.3 ASGIアプリケーションの設定
ASGIアプリケーションの設定も追加する必要があります。これには、asgi.py ファイルをプロジェクトのメインディレクトリ（settings.py があるディレクトリと同じ場所）に作成します。

```python 
# asgi.py

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')  # 'myproject'はあなたのプロジェクト名に置き換えてください

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    # ... 他のプロトコルタイプのルーターもここに追加できます
})
```

#### 4. ルーティングの設定
最後に、WebSocketのルーティングを設定します。これには、routing.py ファイルをアプリケーションのディレクトリに作成し、以下のように記述します。

```python
# routing.py

from django.urls import re_path

from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/some_path/$', consumers.MyConsumer.as_asgi()),  # 'some_path'と'MyConsumer'はあなたの設定に応じて変更してください
]
```

そして、asgi.py ファイルを以下のように更新して、WebSocketのルーティングを追加します。

```python
# asgi.py

# ... (他のインポート文)
from myapp import routing  # 'myapp'はあなたのアプリケーション名に置き換えてください

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter(
            routing.websocket_urlpatterns
        )
    ),
})
```
以上で、Django ChannelsでRedisをバックエンドに設定する準備が整いました。これで、WebSocketを使用してリアルタイムの通信を行うアプリケーションを開発することができます。

### おわりに

redisを使うにしてもどういう風にDjangoと連携するのか想像できないというような人向けにコード付きで手順の例を載せてみました。

誰かの役に立ちますように！
eclipsでspringbootのhelloworldでつまづいて２か月かかりました。gitもつまづきました。


## eclipsでspringbootのhelloworldでつまづいて２か月かかりました。

7月にspringbootに手を出し、永遠にwhite pageのエラーが出まくって放置していたものを
仕事が暇なある日、学習再開したら成功したので、うれしくて記事にしてみました。

### 何につまいたのか
有名なSpringboot入門サイトやyoutubeの入門に手を付けてみたのですが
バージョンの違いなのかwhitelabel error pageのエラーが出てしまいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492033/6681bb75-3c31-2d0a-73a7-64c279374cab.png)
（画像は借り物です。）

参考にしたサイト
https://medium-company.com/spring-boot%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89/

https://www.youtube.com/watch?v=8UERVg5c_HM

（説明に利用されているeclipsとバージョンを合わせれば上手くいくことがあります）

#### 調査してみたが解決には至らず放置

エラー内容等で検索してよく出てきたエラー要因は
・ファイルの保存先に誤りがある。
・コントローラーjavaで誤りがある。（アノテーションとか）
の2点がよくあげられており、そちらに重点を置いて対策を打ってみたものの効果がなく
環境要因を疑って、いろいろな設定を見たりしていました。

そして3日でギブアップしつつ、２週間に一度トライしていました。


### 結局のところ

xmlの修正漏れでした。

こちらを参考に手順通り作成した結果うまくいきました
https://qiita.com/t-shin0hara/items/687085ec34ae78ca2260

その後エラーを起こしていたプロジェクトのxmlも同じように変更を入れたところ。
whitepage➡error.htmlが表示されました。
エラーかよ
と思いつつ、確認してみたところurlに誤りがあり、修正したら正しく表示されました。

# eclipsのgitもつまづきました。

gitは普通に手順書を見たのですが30分ほど躓きました
gitパスワード用にアクセストークンの発行が必要なのですがそこがわかりませんでした。


##### 1,githubから以下の手順でアクセストークンを発行します。
GitHubの右上アカウントをクリックして
「Setting」→「Developer settings」→「Personal access tokens」→「tokens (classic)」と進んで「 Generate a personal access token」をクリックします。
アクセストークンの設定を進めると以下のように黒塗りのエリアにトークンが出てくるので
こちらをパスワードに利用します。（メモ帳などにコピーして手順書に移りましょう）
この手順を把握しておけば、あとはマニュアルも不要かもしれません。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492033/475191e5-beb5-de93-366b-8318d3a96ff3.png)

https://boukenki.info/eclipse-git-push-cant-connect-to-any-repository-%E6%9C%AA%E8%AA%8D%E8%A8%BC/


##### 2,手順書を見ながら進める。
　※パスワードにはアクセストークンを入れる。
雑な説明で申し訳ありませんが、gitpushはこちらの手順書を見ることをお勧めします。
画像で分かりやすく解説しており、初心者にはうってつけの資料です。

　https://yuta-iwase.github.io/doc/pdf/github_tutorial.pdf
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492033/c1e1e823-6440-8d33-1bfc-fd2fb76e2e2f.png)


以上で作業は完了です。

git解決はこちらのQAも参考にしました。

https://qiita.com/ikumi1025193/questions/59ec1894f747af722df0

お借りした画像の元ネタ

https://images.app.goo.gl/H6tZkiceWBswpnn27
Amazon Linux 2 の ClamAV で ERROR: Could not connect to clamd on LocalSocket /run/clamd.scan/clamd.sock: Permission denied

# はじめに

オープンソースのアンチウイルスソフトの [ClamAV] で思わぬ権限エラーに遭遇しました。一応対処できたのでその方法をここに残しておきます。

# TL;DR

`/usr/lib/systemd/system/clamd@.service`（サービス起動スクリプト）で `/run/clamd.scan/` の所有者グループに tomcat を指定することで解決。

```:/usr/lib/systemd/system/clamd@.service
[Service]
～～～
ExecStartPost = /bin/bash -c 'chown root:tomcat -R /run/clamd.scan/'
～～～
```

# システム構成

|役割|名称|
|-|-|
|OS|[Amazon Linux 2]|
|Webサーバー|[Tomcat 8.5][Tomcat]|
|アンチウイルスソフト|[ClamAV]|

```mermaid
flowchart TD

Webブラウザー
subgraph AmazonLinux2
  Tomcat
  ClamAV
end

Webブラウザー --> |ファイルアップロード| Tomcat
Tomcat --> |ウイルスチェック| ClamAV
```
# エラー内容

[Tomcat] 経由でファイルアップロードを実行したらエラーになりました。

試しに以下の様にコマンドを実行してみたところ、エラーが発生しました。

```bash
$ sudo -u tomcat clamdscan test.txt
ERROR: Could not connect to clamd on LocalSocket /run/clamd.scan/clamd.sock: Permission denied

----------- SCAN SUMMARY -----------
Infected files: 0
Total errors: 1
Time: 0.000 sec (0 m 0 s)
Start Date: 2023:10:03 16:12:09
End Date:   2023:10:03 16:12:09
```

# 施策１- 未解決 :disappointed_relieved:

`chown -R root:tomcat /run/clamd.scan/` を実施してみたところ、エラーは出なくなったのですが、システムを再起動したらこの設定が元に戻ってしまいました。

# 施策２- 未解決 :disappointed_relieved:

`/etc/clamd.d/scan.conf` を修正しました。

```diff_conf:/etc/clamd.d/scan.conf
-#LocalSocketGroup virusgroup
+LocalSocketGroup tomcat
```

しかし、エラーが出る状況を改善できませんでした。
ディレクトリのアクセス権限が tomcat ではないのが悪いみたいです。

```bash
$ sudo ls -al  /run/clamd.scan/
合計 0
drwx--x---  2 clamscan virusgroup   60 10月  3 16:09 .
drwxr-xr-x 31 root     root       1040 10月  3 16:09 ..
srw-rw-rw-  1 root     tomcat        0 10月  3 16:09 clamd.sock
```

# 施策３ - 解決 :thumbsup:

`施策１` の方針が良さそうなので、あとはシステムを再起動しても設定が反映されるようにすれば良いはずです。

というわけで、以下の様に clamd の起動スクリプトで `ExecStartPost` を設定しました。
※参考資料：https://qiita.com/JhonnyBravo/items/a28074c20fa9adf02be3

```:/usr/lib/systemd/system/clamd@.service
[Service]
～～～
ExecStartPost = /bin/bash -c 'chown root:tomcat -R /run/clamd.scan/'
～～～
```


システムを再起動してもエラーが出なくなりましたー。

```bash
$ sudo -u tomcat clamdscan test.txt
test.txt: OK

----------- SCAN SUMMARY -----------
Infected files: 0
Time: 0.003 sec (0 m 0 s)
Start Date: 2023:10:03 17:50:58
End Date:   2023:10:03 17:50:58
```

# まとめ

アップロードされたファイルのウイルスチェックを [ClamAV] を使って実装してみましたが、思わぬ権限エラーに遭遇しました。[ClamAV] の設定ファイルだけではうまく解決できなかったので、サービス起動スクリプトで強引に所有者を変更することで解決できました。

ここではあっさり記載していますが、実際にはエラーを解決するまでに 2 時間程費やしました。

ITシステムにおける問題解決のアプローチ方法が多岐にわたることを改めて実感しました。:smiley:

[ClamAV]: https://www.clamav.net/
[Tomcat]: https://tomcat.apache.org/
[Amazon Linux 2]: https://aws.amazon.com/jp/amazon-linux-2/
【Go】make 関数とは？

# `make`関数について

Go言語には、特定の型を初期化するための関数、`make`があります。この関数を理解することで、Goのデータ構造をより効果的に使用することができます。

### `make`って何？

`make`関数は、Goのいくつかの特定の型（スライス、マップ、チャネル）を初期化して、使用可能な状態での値を返すための関数です。

# 作成できる型

### 1. スライスの初期化

スライスは、配列の部分的なビューを提供するデータ構造です。`make`を使用することで、指定したサイズと容量のスライスを生成できます。

```go
s := make([]int, 5)  // 長さ5、容量5のintスライス
```

### 2. マップの初期化

マップは、キーと値のペアを保存するためのデータ構造です。`make`を使用して、新しい空のマップを作成できます。

```go
m := make(map[string]int)  // stringをキーとし、intを値とするマップ
```

### 3. チャネルの初期化

チャネルは、ゴルーチン間での通信や同期をサポートするデータ構造です。`make`でチャネルを初期化すると、データの送受信が可能になります。

```go
ch := make(chan int)  // int型のデータを送受信するためのチャネル
```

# まとめ

Go言語の`make`関数は、特定の型（スライス、マップ、チャネル）を初期化し、すぐに使用できるようにするための便利なビルトイン関数です。

https://pkg.go.dev/builtin#make
Leafmapを使用してデータを地図上に可視化

# はじめに
地図アプリを作成する時にJavaScriptのLeafletを使用することが多いですが、
Pythonでもライブラリがあります。
PythonだとFoliumが有名だと思いますが、
今回、LeafmapというPythonのライブラリを使って地図上にデータを可視化するコードを書いていきます

# Leafmapの特徴
+ インタラクティブな地図の作成が容易
+ 豊富なベースマップの選択
+ JupyterやGoogle Colaboratoryとの互換性

・Leafmap
https://leafmap.org/

Leafmapで作成したアプリのデモです
![68747470733a2f2f7765746c616e64732e696f2f66696c652f696d616765732f6c6561666d61705f64656d6f2e676966.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/e4cd1bfd-5378-8d2d-e0a4-cbc6bb174f6e.gif)
# Leafmap vs Folium
FoliumもPythonでの地図可視化に人気のあるライブラリですが、Leafmapはより多くのベースマップの選択や、簡単なインターフェースを提供しています。
また、特定のデータセットに対する可視化機能もLeafmapの強みとなっています。

# 環境構築
```shell
pip install leafmap
```

# 地図を作成
```python:make_map.py
import leafmap

m = leafmap.Map()
m.to_html('./map.html')
```

"python make_map.py"を実行するとローカルに地図が作成されると思います。
開いてみます
![screencapture-127-0-0-1-5500-map-html-2023-09-22-14_55_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/285cf4ef-1ebc-5c55-ec5b-57bff796f6b2.png)

パラメータを何も設定していないため地図の中心がイギリスになっています。

center属性で日本の緯度・経度を設定すると、htmlを開いた時に日本が中心に表示されます。
```
m = leafmap.Map(center=(30, 135))
```

### ベースマップを変更
```python
m.add_basemap("OpenTopoMap")
```
![screencapture-127-0-0-1-5500-map-html-2023-09-22-15_01_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/a189fa70-eda7-1ad2-0d5c-7bdffeb8e9b6.png)

### XYZタイルレイヤーを追加
```python
m.add_tile_layer(
    url="https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}",
    name="Google Satellite",
    attribution="Google",
)
```
![screencapture-127-0-0-1-5500-map-html-2023-09-22-15_06_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/6093c182-8a4c-6018-adbe-9f8d1c44c1df.png)

### ヒートマップ
人口のヒートマップを作成します
```python
in_csv = "https://raw.githubusercontent.com/opengeos/leafmap/master/examples/data/world_cities.csv"
m.add_heatmap(
    in_csv,
    latitude="latitude",
    longitude='longitude',
    value="pop_max",
    name="Heat map",
    radius=20,
)
colors = ['blue', 'lime', 'red']
vmin = 0
vmax = 10000
m.add_colorbar(colors=colors, vmin=vmin, vmax=vmax)
m.add_title("World Population Heat Map", font_size="20px", align="center")
```
![screencapture-127-0-0-1-5500-map-html-2023-09-22-15_22_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/62800eea-f3f0-4128-652d-69ea96f1252b.png)

# おわりに
geojsonファイルを読み込んだデータを地図に可視化することも可能なので、
Foliumと同様にgeopandasでread_fileしたDataFrameをLeafmapの関数のパラメータに設定すると地図上にラスター/ベクターデータとして出力可能です。
GISに興味のあるエンジニアの方でも非エンジニアの方でもやってみてください！

# 備考
・Leaflet
https://leafletjs.com/

・Folium
https://python-visualization.github.io/folium/latest/

一部の画像は下記より引用させていただいています
https://leafmap.org/notebooks/00_key_features/#set-control-visibility

データはLeafmapのGitHubにあるデータを使用することにします
https://github.com/opengeos/leafmap/tree/master/examples/data
「提升你的就業競爭力：掌握英文履歷、自我介紹、CV與面試技巧」


近年來，全球化的趨勢越來越明顯，許多公司都在積極拓展海外市場，也因此對求職者的英文能力有了更高的要求。對於許多想要在國際舞台上展現自己的人來說，掌握英文履歷、自我介紹、[CV](https://www.apexcharity.org/news/3/88)與面試技巧已成為必備的能力。在這篇文章中，我們將一起來探討如何提升自己的就業競爭力，並掌握這些重要的英文求職技巧。

英文履歷

首先，讓我們來看看[英文履歷](https://www.apexcharity.org/news/3/91)。與中文履歷不同的地方在於，英文履歷通常較為簡潔，一般建議不超過兩頁。因此，你需要精簡地撰寫自己的個人資料、學歷、工作經驗、專業技能與專業證書等。同時，也建議使用條理分明的格式，以便讓人閱讀。

另外，英文履歷應該要用較為正式的語氣撰寫，避免使用口語化的詞彙。同時，也要注意避免錯誤的文法與拼字，不僅會降低求職者的形象，也可能會造成對方誤解你的能力。最後，建議使用常用的字型與字體，並避免使用太過花俏的排版，以免影響閱讀。

自我介紹

接下來是[英文自我介紹](https://www.apexcharity.org/news/3/92)，也是在求職過程中最重要的一部分。如何在短短的幾分鐘內讓招聘人員對你留下深刻的印象，就看你的自我介紹能否做到精准、簡潔且吸引人。

首先，應該在自我介紹中提及你的姓名、年齡、背景等基本資訊，讓對方對你有基本的了解。接著，可以提及你的學歷、專業技能、工作經驗等重要資訊，但要避免冗長的敘述，只需點出重點即可。同時，也可以舉自己在過去工作中所遇到的挑戰與解決的方法，以顯示自己的解決問題能力。

此外，對於想要申請的公司，最好能提前做一些研究，了解公司的文化和理念，並在自我介紹中提及對該公司的認識和興趣，這將讓招聘人員感受到你對該公司的熱誠。最後，還要注意適時地調整自己的語速和語調，讓自己的自信和興趣表露無遺。

CV

CV（Curriculum Vitae）又稱為求職簡歷，是求職者提供給雇主的一份詳細履歷，通常會列出個人資料、學經歷、獎項、證書等。撰寫CV時，要特別注意觀察各公司的要求，並根據要求調整自己的CV。如果是申請特定的職位，也可以將相關的工作經驗和專業技能放在前面，讓招聘人員更容易注意到。

同樣地，CV也要避免使用口語化的詞彙，並注意文法和拼字的準確性。此外，CV應該要有一個清晰的結構，以便閱讀者可以一目了然地找到想要的資訊。在撰寫過程中，也可以參考一些範例來豐富自己的表達方式。

面試

最後一個也是最重要的就是面試。在準備面試前，應該要提前做一些功課，了解公司的背景、文化和該職位的要求。同時也可以先思考一些常見的面試問題並準備答案，以免面試時手足無措。

面試時，應該要注意自己的舉止和語言表達，保持自信和積極的態度。在回答問題時，可以先聽完再說，避免倉促回答。同時也應該要展現自己的專業能力和對該職位的熱誠，讓對方感受到你的能力和興趣。

最後，面試後還要記得感謝對方的時間並表達對該職位的興趣，這也是一個加分的機會。若能經常練習和參加面試，也能讓自己更加熟練地應對不同的面試環境。

總結

總的來說，掌握英文履歷、自我介紹、CV與[英文面試](https://www.apexcharity.org/news/3/93)技巧是提升就業競爭力的重要一環。這些技巧不僅適用於海外求職，也能在國內競爭激烈的求職市場中幫助你立於不敗之地。因此，不妨花點時間和精力去學習和優化自己，在未來的求職過程中能夠更加游刃有余。相信在不久的將來，你會拿到心儀的工作，站在世界舞台上發光發熱。
Flutter ProviderとViewを分ける

●現状、やりたいこと
viewファイルでリストの並べ替えをしている。
より見やすいコードにするために

「viewは画面構成」
「providerはListの更新等の動作」
明確に役割分担をしたい。

●理想の動き
providerにListの並べ替える関数を作成し、
providerにある関数をviewに呼び出したい。

今回はこちらの式を使った

関数の定義 
基本的な関数の定義は次のようになります。 
戻り値の型 関数名 (仮引数の型 仮引数名) 
{ return 戻り値; }

★before
todo_list.dart【view】

    // isCompletedがtrueになっているTodoListのみのリストを再描画する
    final completedTodoList = todoList.where((todo) => todo.isCompleted).toList();

list_provider.dart【provider】

未記入

★after
todo_list.dart【view】

    // listProviderをnotifire(更新) completedTodoListの返り値で書き換え（Listを並び替え)
    final completedTodoList = ref.watch(listProvider.notifier).completedTodoList();

list_provider.dart【provider】

　//並べ替えたいListの型 completedToDoListという関数を作成　並べ替えたリストの結果（返り値）を返す（return）
  List<ToDo> completedTodoList() {
    return state.where((todo) => todo.isCompleted).toList();
}

結論、どちらのコードでも同じ動きになるのだが、保守性や見易さを考えるとviewとproviderそれぞれ役割分担をすると良い。

https://eda-inc.jp/post-5000/
ChatGPTへログインできない不具合が起きた時の話

## ある日突然ChatGPTへログインできなくなり質問を投稿

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1737197/1a5c975d-1bd1-a92e-e9d2-d4e5858cfca9.png)
ChatGPTを仕事で使用しているため、ある日突然この状態になりパニック
ネットで情報検索すると一部似たような人が見受けられる
ということは、自分以外にもいるので何らかの不具合かなと思い至りましたが
急ぎ使いたいこともあり、Qiitaへ質問を投稿しました。

## いただいた回答

> **Chromeの設定/プライバシーとセキュリティ/セキュリティ/セキュアDNSを使用する**
> **次を使用の部分でGoogle (Public DNS)を選択**

こちらは会社管理上変更できませんでした

> **ホワイトリストへの登録**

こちらは対応しました

しかし改善されずにいると
翌日、フォーラムでの声が届いたのか急にログインできるように。

しかし、本日、またログインできない状況に陥りました。


## 解決方法
フォーラムでこの不具合のスレッドをずーっと読み
ネットワークのモニタリングを行ったところ
**新しく追加されたドメイン 「cdn[.]oaistatic[.]com」**
これが弾かれていました。

同じような状況の方の参考になれば幸いです。

## 参考
https://community.openai.com/t/main-topic-chatgpt-not-loading-completely-cant-log-in-only-plain-text-free-research-preview-chatgpt-august-3-version-issue-sept-20-26-from-new-domain/384245
AWS SNSとSQSのファンアウト構成についてメモ

# はじめに
AWS SNSとSQSのファンアウト構成についてメモ

# 参考
https://www.slideshare.net/AmazonWebServicesJapan/20190717-aws-black-belt-online-seminar-amazon-simple-queue-service

# Amazon SNS(Simple Notification Service)とは
Amazon SNSは、Amazon Web Servicesのフルマネージドな通知サービスです。SNSを使用すると、アプリケーションやユーザーにスケーラブルなプッシュ通知、SMS、Lambda関数、HTTPSエンドポイント、SQSキューなど、さまざまなエンドポイントのSNSトピックにサブスクライブ(メッセージ送信)できます。

### 主な特徴と機能

- **トピックとパブリッシュとサブスクライズ**:
  - トピック
      - 利用者はトピックを作成し、そのトピックにメッセージを発行できます。
  - パブリッシュ
      - APIなどから特定のトピックにメッセージを発行すること。
      - このメッセージは、そのトピックにサブスクライブしている全てのエンドポイントやサービスに配信されます
  - サブスクライブ(定期購読)とは
      - トピックが受信するメッセージを受信したいリソースを登録して、リソースがメッセージを受信すること
      - メッセージを購読するリソース
      - Eメール、SMS、Lambda関数、HTTPSエンドポイント、SQSキューなど、さまざまなエンドポイントとしてSNSトピックにサブスクライブできます。

- **ファンアウトとは**
  - 一つのメッセージを複数のサブスクライバーやエンドポイント（SQSキュー、Lambda関数、Eメール、SMSなど）に同時に配信する能力。
  - `通常はSQSがサブスクライブして利用する構成が一般的？ SNS -> SQS -> リソース`


### 流れ
* トピックの作成
    * まず、特定のイベントやサブジェクトに関連するメッセージの集合に対応するトピックをSNSで作成します。

* サブスクリプション
    * 次に、そのトピックにメッセージを受け取りたいエンドポイント（例: Email, SMS, AWS Lambda, SQSなど）をサブスクライブします。サブスクリプションを作成する際には、通知を受け取る方法やエンドポイントの詳細を指定します。

* メッセージの発行
    * APIなどからトピックにメッセージが発行されると、そのメッセージはサブスクライブされているすべてのエンドポイントに配信されます。
    * 例えば、あるトピックにEメールとLambda関数をサブスクライブしている場合、そのトピックにメッセージが発行されると、指定されたEメールアドレスにEメールが送信され、同時にLambda関数も実行されます

# AWS SQS(Amazon Simple Queue Service)とは
SQSはAmazon Web Services（AWS）の提供する完全にマネージドなメッセージキューイングサービスです。アプリケーション間でメッセージを送受信する際のスケーラビリティ、信頼性、簡単な統合を提供します。

`送信サービス -> SQS -> 受信サービス`
あるサービスからからメッセージを受け付け、SQSをポーリングしている受信サービスがメッセージを受け取り、特定の処理を実行する
(後述するSNSとSQSの連携例がわかりやすいかもしれない)

## 特徴
* スケーラビリティ
    * SQSは、トラフィックの増減に関わらず、無限にスケーリングすることができます。

* 信頼性
    * メッセージは複数のサーバーに冗長に保存されるため、メッセージの喪失を防ぐことができます。

* デリバリー保証
    * SQSは、メッセージが少なくとも一度は処理されることを保証します。

* デッドレターキュー
    * 繰り返し処理に失敗するメッセージを特定のキューに移動させることができます。

* 動的な可視性タイムアウト
    * メッセージの再処理を制御することができます。

* スケーリングとスループット
    * SQSは高いスループットを持ち、大量のメッセージを効率的に処理する能力があります。これにより、突発的なトラフィックの増加や大量のメッセージが突如発生した場合でも、メッセージは確実にキューに保存され、順次処理されます。
    
# SNSでSQSを使うメリット
* SNSとSQSを組み合わせることで、SQSの特徴を享受でき、SQSを利用してファンアウト構造をよりシンプルに、よりスケーラブルに実現できる。
* SNSの特定の特定をSQSがサブスクライブすること
* SNSだけでもできるけで、SQLを使うことでより信頼性、冗長性が向上するということ

## SQSを用いたファンアウト構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273424/0a067031-baba-0fa0-830e-66a2a528a7e3.png)

コンシューマは、通常、キューを定期的にポーリングして新しいメッセージが来ていないかを確認します。メッセージが存在する場合、コンシューマはそのメッセージを取得して処理を行い、処理が完了したらそのメッセージをキューから削除します。

##  SQSを用いたファンアウトシナリオ例 
**オンラインストアでの商品の購入**

消費者購入 - > API実行 -> SNSトピックにパブリッシュ -> 複数のSQSがサブスクライブ　-> 複数のコンシューマが受信して特定処理を実施
(メッセージ: 「商品が購入された」というイベントを示すメッセージがSNSによって発行)

* 複数のコンシューマ:
  * 在庫管理システム: 購入された商品の在庫を減少させる。
  * 会計システム: 購入情報に基づいて請求処理を行う。
  * 通知システム: 購入者に購入完了のメール通知を送る。
  * 統計・分析システム: 購入データを集計し、分析やレポートを作成する。

上記のシナリオで、SNSを使って「商品が購入された」という一つのメッセージを発行(SNSトピックにパブリッシュ)すると、それぞれのSQSキューにそのメッセージが配信されます。
各SQSキューに関連付けられたコンシューマ（在庫管理、会計、通知、統計・分析）は、そのメッセージを受け取って独自の処理を行います。

このように、一つのイベント（メッセージ）が発生した際に、**それに関連する複数のタスクを並列に、かつ効率的に処理することが可能になります**。SNSとSQSを組み合わせることで、このようなファンアウト構造をシンプルに、スケーラブル(SQSのメリットの享受)に実現できるのです。
【Rust】HashMap基本

# HashMapとは？

`HashMap`は、**キー**と**値**のペアを保存するためのデータ構造です。特にRustの`HashMap<K, V>`は、`K`型のキーと`V`型の値を保存します。キーは一意であり、それに関連づけられた値を迅速に取得することができます。例えば、人の名前をキーとして、その電話番号を値として保存することが考えられます。

# 主な特徴

- **キーの一意性**: 同じキーに対して複数の値を持つことはできません。新しい値でキーを更新すると、古い値は上書きされます。
- **型安全**: Rustの`HashMap`はジェネリック型を使用しており、キーと値の型がコンパイル時に確定します。これにより、不正な型のデータの挿入や取得を防ぎます。

# 使用例

たとえば、人々の名前とその電話番号を保存したい場合、`HashMap`を次のように使用できます

```rust
use std::collections::HashMap;

let mut phone_book: HashMap<String, String> = HashMap::new();
phone_book.insert(String::from("Alice"), String::from("090-1111-2222"));
phone_book.insert(String::from("Bob"), String::from("090-2222-3333"));

let number = phone_book.get("Alice");
```

このコードは、2人の連絡先を`phone_book`という名前のHashMapに追加しています。そして、`get`メソッドを使用してAliceの番号を取得します。

# まとめ

`HashMap`は、キーと値のペアを保存する便利なデータ構造です。Rustの`HashMap<K, V>`は型安全性や所有権のモデルなど、Rust独特の特性も持っています。これにより、データの迅速かつ安全なアクセスが可能となります。

https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html
【Dart】リダイレクトコンストラクタとは？

# リダイレクトコンストラクタとは？

Dartでは、1つのコンストラクタがクラス内の別のコンストラクタに「リダイレクト」することができます。これを「リダイレクトコンストラクタ」と呼びます。主に、異なる入力や設定で同じクラスの別のコンストラクタを呼び出す際に使用されます。

### リダイレクトコンストラクタの特徴
1. **コードの再利用**: 同じクラス内の既存のコンストラクタのロジックを再利用できるため、コードの重複を減らすことができます。
2. **シンプルな構文**: コンストラクタ内で単に `this` キーワードと他のコンストラクタの名前を使ってリダイレクトします。

### リダイレクトコンストラクタの基本的な使用方法

```dart
class Point {
  int x, y;

  // 主コンストラクタ
  Point(this.x, this.y);

  // 名前付きリダイレクトコンストラクタ
  Point.alongXAxis(int x) : this(x, 0);
}
```

上記の例では、`Point.alongXAxis`という名前付きコンストラクタは、y座標を0として、主コンストラクタ`Point`をリダイレクトしています。

# まとめ
Dartのリダイレクトコンストラクタは、クラスのコンストラクタ間でロジックを共有することを容易にします。これにより、コードの整理とメンテナンスがしやすくなります。

https://dart.dev/language/constructors#redirecting-constructors
【Dart】初期化リスト(Initializer list)とは？

# 初期化リスト(Initializer list)とは
Dartのコンストラクタでは、インスタンス変数を初期化するための特別な構文、初期化リストを提供しています。この機能を使用すると、コンストラクタの本体が実行される前に変数の初期化を行うことができます。

### 初期化リストの特徴:
1. **コンストラクタ本体の前に実行**: 初期化リストは、コンストラクタの中括弧 `{}` の前、コロン `:` の後に書きます。
2. **final変数の初期化**: `final`で宣言された変数は、初期化リストを通じて初期化することが多いです。これは`final`変数が一度だけ値の設定が可能であるためです。
3. **複数の初期化**: 初期化リストでは、カンマ `,` を用いて複数の変数を順序正しく初期化することができます。

### 初期化リストの基本的な使用方法:

```dart
class Point {
  final int x;
  final int y;
  int z;

  Point(this.x, this.y);

  Point.fromMap(Map<String, int> data) 
      : x = data['x'] ?? 0, 
        y = data['y'] ?? 0,
        z = data['z'] ?? 0;
}
```

上記の`Point.fromMap`コンストラクタでは、初期化リストを使用して、マップから`x`, `y`, `z`の値を取得し、それらの値が`null`の場合は`0`をデフォルト値として設定しています。

# まとめ
Dartの初期化リストは、インスタンス変数の初期化を行うための強力なツールです。特に、`final`変数や、コンストラクタの本体実行前にいくつかの処理を行いたい場合に非常に有用です。

https://dart.dev/language/constructors#initializer-list
【Dart】名前付きコンストラクタの基本

# はじめに
ほとんどのオブジェクト指向プログラミング言語には、クラスのインスタンスを生成するための「コンストラクタ」という特別なメソッドがあります。多くの言語では、1つのクラスには複数のコンストラクタを持つことができるものの、それぞれのコンストラクタは異なるシグネチャ（パラメータの型や数）を持つ必要があります。

Dartでは、そのような制限を回避するために「名前付きコンストラクタ」を導入しています。これにより、クラスには複数のコンストラクタを持つことができ、それぞれのコンストラクタにはユニークな名前を付けることができます。

#### 例

```dart
class Point {
  double x, y;

  // 通常のコンストラクタ
  Point(this.x, this.y);

  // 名前付きコンストラクタ
  Point.origin()
      : x = 0,
        y = 0;
}

void main() {
  var p1 = Point(2, 3);       // 通常のコンストラクタを使用
  var p2 = Point.origin();   // 名前付きコンストラクタを使用

  print('p1: (${p1.x}, ${p1.y})');
  print('p2: (${p2.x}, ${p2.y})');
}
```

この例では、`Point`クラスには2つのコンストラクタがあります。1つは通常のコンストラクタで、もう1つは`origin`という名前付きのコンストラクタです。`Point.origin()`コンストラクタは、座標の原点（0, 0）を表すPointオブジェクトを生成します。

名前付きコンストラクタは、特定の初期状態や設定を持つインスタンスを生成する場合などに非常に便利です。また、名前を持つことで、それぞれのコンストラクタがどのような目的で提供されているのかをコードを読む人に明確に伝えることができます。

# 名前付きコンストラクタの基本的な書き方
名前付きコンストラクタは、クラス名の後にドット（`.`）とその後にコンストラクタ名を付けて定義します。

```dart
class ClassName {
  ClassName.constructorName();
}
```

## 名前付きコンストラクタの例
以下は、`Rectangle`クラスの例です。このクラスには、通常のコンストラクタと2つの名前付きコンストラクタ（`square`と`fromPoints`）が含まれています。

```dart
class Rectangle {
  int width;
  int height;
  int left;
  int top;

  // 通常のコンストラクタ
  Rectangle(this.left, this.top, this.width, this.height);

  // 名前付きコンストラクタ: 正方形を生成
  Rectangle.square(int size)
      : width = size,
        height = size,
        left = 0,
        top = 0;

  // 名前付きコンストラクタ: 2つの点からRectangleを生成
  Rectangle.fromPoints(Point a, Point b)
      : left = a.x,
        top = a.y,
        width = b.x - a.x,
        height = b.y - a.y;
}
```

## 名前付きコンストラクタの特徴と利点

1. **明確性**: 名前付きコンストラクタは、その名前を通じてコンストラクタの目的や動作を明確に示すことができます。
  
2. **柔軟性**: 同じシグネチャの異なるコンストラクタを複数持つことができます。これは、他の多くのプログラミング言語では不可能です。
  
3. **コードの可読性**: 名前付きコンストラクタを使用することで、インスタンスの生成時に、そのコンストラクタが何を意味しているのかを直感的に理解することが容易になります。

例:
```dart
var square = Rectangle.square(4); // これは正方形であることが明確
var rect = Rectangle.fromPoints(Point(0, 0), Point(2, 4)); // 2つの点から生成されることが明確
```

# まとめ
Dartの名前付きコンストラクタは、クラスのインスタンスを生成する際の柔軟性と明確性を向上させる便利な機能です。クラスに複数の初期化方法や特定のシナリオが必要な場合に特に役立ちます。
【ChatGPT無】箇条書きでの出力数をどうすればコントロールできるのか


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

　今回は、箇条書きでの出力数をどうすればコントロールできるのかを確認します。

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　本題の前に、ちょっとニュース。
　・Bingの回答先でマルウェアに？
[Bing Chatの回答にマルウェア入りの広告が紛れ込んでいることが判明](https://gigazine.net/news/20231003-bing-chat-ads-pushing-malware/)
　　　特定のアプリ？を
　　　　ダウンロードすると
　　　　　マルウェアが。
　　　　　　ご注意を。

***
　では、本題に入ります。

　箇条書きで、
　　出力数を
　　　指定することはできます。

　でも、
　　出力数以上にしようとすると
　　　出力数以上の出力が
　　　　得られない場合ばかりです。

　これは、おそらく
　　指定の仕方が
　　　ダメなのでしょうね。
***
　そこで、
　　どうすれば
　　　コントロールできるのかを
　　　　確認しようと思います。

　まずは、
　　基本のPrompt。
```Text:基本のPrompt
未確認な事象を教えてください。
箇条書き（説明不要）でお願いします。
```
　「未確認の事象」とは、
　　例えると、「UFO」とか
　　　「ネス湖のネッシー」
　　　　なんかのことです。
　　　　　出そうと思えば、
　　　　　　たくさんありますw

　このPromptでは、
　　10個、出力されます。
　　　指定しないと、
　　　　だいたい5個や10個が
　　　　　多い気がします。
***
　次に、最初の行を
　　「未確認な事象を
　　　**できるだけ**
　　　　教えてください。」
　　　　　とします。
　　　箇条書きの行は変えません。

　このPromptでも
　　10個です。
***
　次に、最初の行を
　　「未確認な事象を
　　　**10個に限らず、できるだけ**
　　　　　教えてください。」
　　　　　とします。

　結果は、
　　10個。
***
　次に、最初の行をそのままに、
　　1行追加。
　　「未確認な事象を
　　　　教えてください。
　　　**10個に限らず
　　　　教えてください**。」
　　　　　とします。

　結果は、
　　10個。
***
　次に、追加した1行を
　　最終行にします。

　結果は、
　　同じく、10個。

　変化ありませんねぇ。
***
　次に、
　　この最終行を
　　　「10個以上教えてください」
　　　　にします。

　結果、
　　変わりました。
　　　20個です。

　よし、
　　この調子で、続けます。
***
　次に、
　　最終行に
　　　「無理にひねり出す
　　　　必要はないですよ。」を
　　　　　付け加えます。

　ハルシネーションしようと
　　思えば、できるような質問
　　　ですからねw

　結果、
　　15個に。
***
　上記で、
　　重複している項目が
　　　ありましたので、最後の行に
　　　　「重複しないでね」と
　　　　　最後に追加しました。

　結果が、
　　10個に減りました。

　なぜ？

　改行したら、
　　20個に。

　 なぜ？
***
　「重複～」を
　　「出力したら、
　　　重複している項目を
　　　　削除してください。」と
　　　　　しました。

　10個に。

　なぜ？
***
　で、
　　このまま、続けます。

　「10個以上教えてください」を
　　「10個を越えるくらいに、
　　　教えてください。」に変更。

　ううむ、
　　10個。

　ここまでくると
　　出力数を出したから、
　　　固定になりやすい？
***
　「10個以上」を
　　「20個以上」に。

　やはり、
　　20個です。

　「100個」と指定すると、
　　100個出してきた。
　　　しかも重複ありありで(泣)
***
　結論としては、
　　欲しい出力数よりも
　　　多い数を指定する
　　　　のが、良い感じです。

　また、
　　重複も出力される可能性も
　　　ありますので、
　　　　自分の目
　　　　（あるいはExcelなどの
　　　　　ツール）にて、
　　　　　　確認すべきです。

　ChatGPTさんは、
　　少しの数であれば、
　　　処理できますが、
　　　　多くなると、
　　　　　難しくなります。

　ある程度の信頼とともに
　　ある程度のハルシネーションを
　　　考慮するように
　　　　しましょう。

　今回は、ここまで。
[JS/TS] xhr (非同期通信オブジェクト)を使ってみる

# xhrとは

xhr（XMLHttpRequest）は、JavaScriptを使用して非同期にサーバーと通信するためのオブジェクトです。これにより、ページ全体を再読み込みすることなく、部分的にデータを更新することができます。

👉 ポイント: xhrはJavaScriptで非同期通信を行うためのオブジェクトです。

## xhrの基本的な使い方

1. **オブジェクトの作成**: まず、XMLHttpRequestオブジェクトを作成します。
   
   ```javascript
   const xhr = new XMLHttpRequest();
   ```

   👉 ポイント: `new XMLHttpRequest()`でxhrオブジェクトを生成します。

2. **通信の設定**: 通信のタイプやURLを設定します。
   
   ```javascript
   xhr.open('GET', 'https://example.com/data');
   ```

   👉 ポイント: `open`メソッドで通信の方法やURLを指定します。

3. **レスポンスの取得**: サーバーからのレスポンスを受け取るための処理を設定します。
   
   ```javascript
   xhr.onload = function() {
       if (xhr.status === 200) {
           console.log(xhr.responseText);
       } else {
           console.error('Request failed.');
       }
   };
   ```

   👉 ポイント: `onload`イベントでレスポンスを処理します。

4. **通信の開始**: 設定した通信を実際に開始します。
   
   ```javascript
   xhr.send();
   ```

   👉 ポイント: `send`メソッドで通信を開始します。
Xcode15でCloud signing permission errorに遭遇

## Cloud signing permission errorに遭遇

Xcode15でアプリのアーカイブを作成してApp Store ConnectにOrganizerを使ってアップロードしようとしたら以下のようなエラーが発生しました。

```text()
Cloud signing permission error
You haven't been given access to cloud-managed distribution certificates.
Please contact your team's Account Holder or an Admin to give you access.
If you need further assistance,
contact Apple Developer Program Support at https://developer.apple.com/contact/.
```

Cloud signingってなんだろ？と思いながらなにかの権限が足りていないのかな？と思ってApp Store Connectで色々みてみました。
で、今回ぶち当たった問題は該当ユーザに「クラウド管理配布証明書へのアクセス」という項目がチェックされていないからでした。

## 解決方法

チェックの入れ方は
1. App Store Connectにログイン
1. 「ユーザとアクセス」を選択
1. 該当のユーザを選択
1. 「その他のリソース」のところを確認
1. 「クラウド管理配布証明書へのアクセス」をチェックする。

Webブラウザの画面はこんな感じになります。
![sonota_resource.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31696/ea23cb88-2801-c057-bcab-5737fb7a6b94.png)

請負開発などで自分ではユーザ権限を変更できない方は管理者にお願いしてください。

私の場合はこれで解決しました。
【Ruby・Rails】mergeメソッドの2つの働き

## はじめに
プログラミング学習をする中で、mergeメソッドの挙動の違いに遭遇したのでまとめてみました。

## 先に結論
Rubyにおける場合と、RailsのActiveRecordにおける場合でmergeメソッドの処理が変わる。

:::note
どのレシーバーに対して使っているかがポイント
:::

## Rubyのハッシュの **merge** メソッド

**2つのハッシュを結合して新しいハッシュを作成します。**
このメソッドは、ハッシュのキーと値を結合し、重複するキーがある場合は後からマージされたハッシュの値が優先されます。
以下は、**merge** メソッドを使用して2つのハッシュを結合する例です。

```ruby
hash1 = { a: 1, b: 2 }
hash2 = { b: 3, c: 4 }
merged_hash = hash1.merge(hash2)

puts merged_hash 
=> **{ a: 1, b: 3, c: 4 }**

```
[Ruby リファレンスマニュアルの説明はこちら](https://docs.ruby-lang.org/ja/latest/class/Hash.html#I_MERGE)

## Railsのストロングパラメーターでよく見る。
使用例

```controllers.rb
private
  def user_order_params
    params.require(:user_order).permit(:postal_code, :prefecture_id).merge(user_id: current_user.id, item_id: params[:item_id])
  end
```
item_id: params[:item_id]で値を入れることができるのは、ルーティングをネストし、URLにitem_idを含めているため。ストロングパラメーターはprivateメソッド以下に記述する。

requireの引数は、モデル名。
permitの引数は、DBのカラム名。

ターミナルで確認できるパラメーター
```
 "user_order"=>{"hoge"=>"", "postal_code"=>"", "prefecture_id"=>"1"}, "commit"=>"購入", "controller"=>"orders", "action"=>"create", "item_id"=>"7"}
```
### mergeメソッドを使う場面
　form_withでユーザーが記入した内容はハッシュの中に、キーと一緒に入っているが、ユーザーが記入しない内容も保存したい時。
例えば、ユーザーのidやその商品のidについては、ユーザーが直接入力することはないが、パラメーターに含めて、DBの保存したい。そのような時に、mergeメソッドを使って、パラメーターに含めたいキーと値を記述する。
上記の例では、user_idをcrrent_user.idから、item_idをURLに含めたparamsから取ってきて、パラメーターに含めている。

## RailsのActiveRecordにおける **merge** メソッドは

**クエリ条件を結合するためのメソッドです。**
これは、データベースクエリに対して追加の条件を結合するために使用されます。例えば、**where** や **joins** の条件を組み合わせてクエリを生成するのに使います。

例えば、以下のように **merge** メソッドを使用してクエリ条件を結合できます。

```ruby
# 最初のクエリ条件を定義
query1 = User.where(role: 'admin')

# さらに条件を追加する
query2 = query1.merge(User.where(status: 'active'))
```

この例では、**query1** と **query2** は異なるクエリ条件を持ちますが、**merge** メソッドを使用して **query1** に **query2** を結合することで、両方の条件を持つ新しいクエリを作成します。

ちなみに、公式ドキュメントにはこう書いてあります。（ざっくり翻訳）

:::note
Railsのmergeメソッドは、ActiveRecord::Relation同士を結合するためのもの。
これを使うと、あるクエリの結果に対して別のクエリの条件を追加することができる。

例えば、Post.where(published: true).joins(:comments).merge(Comment.where(spam: false))というコードは、「公開済みの投稿」＋「スパムでないコメントがついているもの」を取得するためのクエリとなる。

また、Post.where(published: true).merge(-> { joins(:comments) })という書き方でも同じクエリを発行できる。
ここでの-> { joins(:comments) }はProcという特殊なオブジェクトで、この中に書かれたコードがmergeメソッドによって評価される。

このように、mergeメソッドを使えば、複数のクエリの条件を一箇所で管理することができる。
結果としてコードがシンプルになり、繰り返しを避けることもできる
:::
[公式ドキュメントはこちら](https://api.rubyonrails.org/classes/ActiveRecord/SpawnMethods.html#method-i-merge)


## まとめ
:::note
2つの **merge** メソッドは、異なるレシーバー（コンテキスト）で異なる動作をするメソッド。
それぞれのレシーバー（コンテキスト）で **merge** メソッドがどのように使用されるかに注意が必要。
:::

このようなメソッドが他にもあるので、手を動かす中で少しずつ慣れていきたいですね。

## 参考
https://qiita.com/TerToEer_sho/items/c445bad0a9726030d24c
[PHP] Yiiフレームワークの特徴

# Yiiフレームワークとは

Yiiフレームワークは、PHPで書かれた高性能なWebアプリケーションフレームワークの一つです。特に大規模なWebアプリケーションの開発に適しており、短時間で効率的にアプリケーションを構築することができます。

👉 ポイント: YiiはPHPで書かれたWebアプリケーションフレームワークです。

## なぜYiiフレームワークが選ばれるのか

1. **高速性**: Yiiは、ページの読み込み速度やデータベースのクエリ速度を最適化するためのツールを多数備えています。
   
   👉 ポイント: Yiiは高速なページ読み込みを実現します。

2. **拡張性**: Yiiはモジュールやウィジェットといった拡張機能をサポートしており、カスタマイズが容易です。
   
   👉 ポイント: カスタマイズがしやすいのがYiiの特徴です。

3. **セキュリティ**: SQLインジェクションやクロスサイトスクリプティングなどのWeb攻撃からアプリケーションを守るための機能が組み込まれています。
   
   👉 ポイント: Yiiはセキュリティ面でも信頼性が高いです。




## 簡単なコードの例

### モデルの作成

```php
namespace app\models;

use yii\db\ActiveRecord;

class User extends ActiveRecord
{
    public static function tableName()
    {
        return 'user';
    }
}
```

👉 ポイント: YiiではActiveRecordを使用してデータベースの操作を簡単に行うことができます。

### コントローラの作成

```php
namespace app\controllers;

use yii\web\Controller;
use app\models\User;

class UserController extends Controller
{
    public function actionIndex()
    {
        $users = User::find()->all();
        return $this->render('index', ['users' => $users]);
    }
}
```

👉 ポイント: コントローラはアクションを定義し、モデルとビューを結びつける役割を持っています。

## まとめ

Yiiフレームワークは、高速性、拡張性、セキュリティの3つの大きな特徴を持つPHPのWebアプリケーションフレームワークです。簡単なコードを通じて、その効率的な開発スタイルを感じることができます。
Debian 11 に mysql-community-server をインストール

Debian 11 に mysql-community-server をインストールする方法です。
Chromebook の Linux 環境である Debian 11 で確認しました。
次のページと同様の作業を行いました。
[How to Install MySQL 8.0 on Debian 11 Bullseye](https://www.linuxcapable.com/how-to-install-the-latest-mysql-8-on-debian-11/)

## 必要なソフトのインストール

```bash
sudo apt install software-properties-common apt-transport-https wget ca-certificates gnupg2
```

## リポジトリーのインストール

```bash
sudo wget -O- http://repo.mysql.com/RPM-GPG-KEY-mysql-2022 | gpg --dearmor | sudo tee /usr/share/keyrings/mysql.gpg
```

```bash
echo 'deb [signed-by=/usr/share/keyrings/mysql.gpg] http://repo.mysql.com/apt/debian bullseye mysql-8.0' | sudo tee /etc/apt/sources.list.d/mysql.list
```

```bash
echo 'deb [signed-by=/usr/share/keyrings/mysql.gpg] http://repo.mysql.com/apt/debian bullseye mysql-tools' | sudo tee -a /etc/apt/sources.list.d/mysql.list
echo 'deb-src [signed-by=/usr/share/keyrings/mysql.gpg] http://repo.mysql.com/apt/debian bullseye mysql-tools' | sudo tee -a /etc/apt/sources.list.d/mysql.list
```

```bash
sudo apt update
```

## mysql-community-server のインストール

```bash
sudo apt install mysql-community-server
```

## インストールされたことの確認

```bash
sudo systemctl status mysql
```

## サーバーに接続

```text
$ sudo mysql -uroot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.34 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

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

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.34    |
+-----------+
1 row in set (0.02 sec)

mysql>
```
Spring Boot 3.x への移行で、セッション周りではまったこと

# Spring Boot 3.x への移行で、セッション周りではまったこと

たいした話ではないのでのすが、Spring Boot 2.x -> 3.x での移行で、セッション周りではまったことの備忘録です。

## Spring Boot 3.x での変更点

以下にマイグレガイドがあります。

[Spring Boot 3.0 Migration Guide · spring-projects/spring-boot Wiki](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#spring-session-store-type)

それによると、`spring.session.store-type` による明示的な構成はサポートされなくなりました。複数のセッションストアの実装がクラスパス上にある場合は、固定順で使用する実装が選択されるようです。

優先順位は、[Web](https://docs.spring.io/spring-boot/docs/3.0.x/reference/html/web.html#web.spring-session) に記述されていますが、

   1. `Redis`
   2. `JDBC`
   3. `Hazlecast`
   4. `MongoDB`

となっています。

それ以外には、`@EnableRedisHttpSession` などのアノテーションを明示的に指定する方法があります。

今回 Sprint Boot 2.x の構成には、以下があったので **安直に**  `@EnableRedisHttpSession` を指定しました。

```
spring.session.store-type=redis
```

## 外部からの構成変更が効かない

通常はセッションの有効期間は1800秒がデフォルト値ですが、この値を変更したいと思い、`spring.session.timeout` を設定しましたがどうも効いてないようです。 他にも `server.servlet.session.timeout` なども試しましたうまくいきません。

`@EnableRedisHttpSession` を指定しつつ、`application.yml` に以下の設定を行います。

```yaml
spring:
  session:
    timeout: 180s
```

セッションの有効時間を取得するコードを書いてみます。

```java
    @GetMapping("/s1")
    public Map<String, Object> s1(HttpSession session) {
        session.setAttribute("test", "value");
        return Map.of(
            "id", session.getId(),
            "date", (new Date()).toString(),
            "maxInactiveInterval", session.getMaxInactiveInterval());
    }
```

`curl` でアクセスしてみますが、常に `1800` を返します。

```sh
$ curl -s http://localhost:8080/s1 | jq
{
  "date": "Wed Oct 04 11:41:29 JST 2023",
  "id": "e543ea6d-8141-4ad3-8c6f-15bbae3cc7ad",
  "maxInactiveInterval": 1800
}
```

`@EnableRedisHttpSession` を外してみますと、`spring.session.timeout` が効くようになりました。

```sh
curl -s http://localhost:8080/s1 | jq
{
  "date": "Wed Oct 04 11:43:44 JST 2023",
  "id": "a14b4f19-e196-4798-a75b-c35a609be146",
  "maxInactiveInterval": 180
```


クラスパスには `Redis` の実装しか通ってないので、明示的にアノテーションを指定しようがしまいが同じ振る舞いなのですが、明示的にアノテーションを指定すると `spring.session.timeout` が効かないようです。

`@EnableRedisHttpSession` を指定したい場合は、アノテーションにパラメーターを指定する必要があります。（ここで値を可変にする方法が分からなかったので、固定値にしていますが）

```java
@SpringBootApplication
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 360)
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}
```

`curl` でアクセスしてみますと、`360` が返ってきました。

```sh
curl -s http://localhost:8080/s1 | jq
{
  "maxInactiveInterval": 360,
  "id": "7c336543-51a7-4d2c-b2cd-4da747fa4986",
  "date": "Wed Oct 04 11:50:17 JST 2023"
}
```

## まとめ

あとからググってみると、昔からわりとよくある話のようです。以下のような記事がありました。

- [@EnableRedisHttpSession + Spring Boot ignoring server.session.timeout on application.yml - Stack Overflow](https://stackoverflow.com/questions/37303967/enableredishttpsession-spring-boot-ignoring-server-session-timeout-on-applica)

同じ挙動なのに、アノテーション付けると効かないのは、ちょっと分かりづらいですね。

以上
タイムズカー予約のヒヤヒヤ解放: ブックマークレットでの半自動化

## 背景

カーシェアリングのタイムズカーを月になんどか使います。予約のときに日時をプルダウンで選択するのですが、うっかりなわたしは、いつか間違えそうで、いつもヒヤヒヤしています。

![SS 2023-10-04 11.27.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/ff2b263d-c65f-10b0-aa38-ad5b31f98f69.png)

おそらく、カレンダーを見て予約の時間を考えながら、６つの要素を間違えない、というのがストレスなのだと思います。

頻繁に行う操作なので、ブックマークレットにしました。

## ブックマークレット作成

- ブラウザのブックマークバーにブックマークをつくります。名前はなんでもいいですが、`timesBookFill`としました。
- ブックマークのURL欄に、下記のJavaScriptを貼ります。

## ブックマークレットの実行

- 予約サイトを開き、ブックマークバーのブックマークをクリックします。
- 開始日と終了日を入力するプロンプトが出ます。
- `YYYY-MM-DD hh:mm / YYYY-MM-DD hh:mm`形式で入力します。
- プルダウンが選択されます。

![SS 2023-10-04 11.35.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/b4e4972c-a44b-872a-4d03-197a2fad639c.png)

## 実際の運用

エディタ（Obsidian）のデイリーノートに予約日時をメモし、プロンプトにコピーします。作業がそのまま記録になるので、万が一ミスったときも、どこで間違えたかトラッキングできます。

![SS 2023-10-04 11.45.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/ede0889c-93fb-dc88-c0bb-d72e0ecfe8c1.png)


## JavaScript

```javascript
javascript:(function(){
    document.getElementById('dateStartSearch').value = '';
    document.getElementById('hourStartSearch').value = '';
    document.getElementById('minuteStartSearch').value = '';
    document.getElementById('dateEndSearch').value = '';
    document.getElementById('hourEndSearch').value = '';
    document.getElementById('minuteEndSearch').value = '';
    
    var i = prompt('日時を以下のフォーマットで入力：\n"YYYY-MM-DD hh:mm / YYYY-MM-DD hh:mm"', '').split(' / '), sP = i[0].split(' '), eP = i[1].split(' '), sD = sP[0], sT = sP[1].split(':'), eD = eP[0], eT = eP[1].split(':');
    if(sD !== eD && !confirm('開始日と終了日が異なります。これは正しいですか？')) return;
    if(![0,23].some(v => parseInt(sT[0]) >= v) || !["00","15","30","45"].includes(sT[1]) || ![0,23].some(v => parseInt(eT[0]) >= v) || !["00","15","30","45"].includes(eT[1])) {
        alert("時刻のフォーマットが正しくありません。");
        return;
    }

	document.getElementById('dateStartSearch').value = sD + ' 00:00:00.0';
    document.getElementById('hourStartSearch').value = (+sT[0]).toString();
    document.getElementById('minuteStartSearch').value = sT[1];
    document.getElementById('dateEndSearch').value = eD + ' 00:00:00.0';
    document.getElementById('hourEndSearch').value = (+eT[0]).toString();
    document.getElementById('minuteEndSearch').value = eT[1];
})();

```

予約をミスらないための工夫点

- 予約開始日時と終了日時が異なる場合、アラートを出す（処理は進められる）
- 時刻（hh）を１桁にする
- 時刻（mm）の形式をチェックする（値は00, 15, 30, 45のみ）
- スクリプトがうまく動かないときの予防で`-- 選択 --`を選んでおく

## おわりに

定期的に予約作業があり、毎回ヒヤヒヤしていました。これでかなりストレスが減らせるのではないかとおもいます。

## 環境

- Vivaldi: 6.2.3105.56 (Stable channel) （arm64） 
- OS: macOS バージョン14.0（ビルド23A344）
- JavaScript: V8 11.6.189.22
visionOS 1 beta 4 Simulator Runtime （最新版VisionOS エミュレーター）のインストール方法&環境構築

# はじめに
VisionOSのRuntimeはXcode-betaとは別で新しいバージョンが公開されているので、それを実行するためにXcode-betaで有効化する方法をまとめました。

# Xcode-betaのインストール
VisionProのエミュレーターの使用にはXcode-betaのダウンロードが必要になります。
Xcode-betaの使用にはMacが必要です。

[Apple - Developer - More Downloads](https://developer.apple.com/download/all/)

こちらのサイトの検索窓からXcode-betaと検索してインストールしてください
詳しいインストール方法についてはこちらの記事をご覧ください
[VisionProのエミュレーターのインストール方法 -kanakanho](https://qiita.com/kanakanho/items/4dd7448aad63a6beb20a)

# VisionOS Runtimeのインストール

VisinOSのRuntimeも先ほどと同じサイトからダウンロードできます。

こちらのサイトで**visionOS**で検索
[Apple Developer More Downloads ](https://developer.apple.com/download/all/)

最新のRuntimeをダウンロード
![](https://storage.googleapis.com/zenn-user-upload/d1bdce1c2f7f-20231004.png)

ターミナルで以下を実行
```
$ sudo xcode-select -s /Applications/Xcode-beta.app
$ xcodebuild -runFirstLaunch
$ xcrun simctl runtime add "~/Downloads/ダウンロードしたdmg"
```

成功するとこんな感じのメッセージが表示されます
```
D: 82336B3A-0A00-4784-A1CF-EB6F68E2F4B6 xrOS (1.0 - 21N5259j) (Ready)
```

Appleの公式にはsudoなしのコードが書かれていますが、管理者権限がないとこのエラーがでます
```
xcode-select: error: --switch must be run as root (e.g. `sudo xcode-select --switch <xcode_folder_path>`).
```
# 終わりに
VisionProの情報がどんどん公開されて今後が楽しみですね
今はエミュレーターだけですが、エミュレータも更新されていくので新しいものを触っていきましょう！

**参考**
https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes
【Rails】システムスペックで日本語のファイル名をダウンロードするとファイル名が "download" になってしまう場合の対処法

## 発生した問題
Railsのシステムスペックでファイルダウンロードの機能をテストしようとしたが、日本語を含むファイル名だとファイル名がなぜか "download" になってしまう。

```
# 期待するpath
/path/to/downloaded_files/ほげほげ.txt

# 実際のpath
/path/to/downloaded_files/download
```

以下は失敗するテストコード（ヘッドレスChromeを利用するシステムスペック）の例。

```ruby 
click_link 'ダウンロード'

# wait_and_find_download_file は自作のヘルパーメソッド、という想定
download_path = wait_and_find_download_file

expect(download_path).to end_with "ほげほげ.txt"
#=> Failure/Error: expect(download_path).to end_with "ほげほげ.txt"
#=>   expected `"/path/to/downloaded_files/download".end_with?("ほげほげ.txt")` to be truthy, got false
```

とくに、ローカル環境ではパスするのに、CI環境（GitHub Actionsなど）でテストが落ちてしまう。

一方、ファイル名をアルファベットのみにするとテストは問題なくパスする（"abc.txt"など）。

## 対処法
ロケールの設定を日本にする。たとえばGitHub Actions（Ubuntu環境）でテストが落ちる場合、以下のような設定を追加する。

```yaml 
steps:
  # ...

  - name: Set Locale
    run: |
      sudo locale-gen ja_JP.UTF-8
      sudo update-locale LANG=ja_JP.UTF-8
```
Inkscapeでaiファイル形式で保存

## 初めに
Inkscape独自の機能を使うと出来ませんので気をつけましょう。
フィルタとか。

Inkscapeのバージョンは1.3現在です。
![fig_inkscape_ver.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3526103/e2d44cd7-d568-7f48-ec6c-7cb8976ddff5.png)

## 概要
1. 不要なものを全部削除する
2. オブジェクトとテキストをパスに変換する
3. PDF形式で保存
4. 保存した拡張子をaiに変更

## 保存の仕方
メニューから
`ファイル` -> `名前を付けて保存...`
を選択

ダイアログの
`ファイル拡張子を自動的につける`
にチェックを入れて、
保存形式を`pdf`を選択し、
`保存`ボタンを押下

![fig_inkscape_pdf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3526103/d58f6404-5daa-0a40-0ffa-ada577f2417b.png)

`テキストをパスに変更`を選択し、
`OK`ボタンを押下

保存したファイルの拡張子を`pdf`から`ai`に変換

以上です。
UI部品の名前参考

## デザインUIパーツ名参考

<https://mui.com/material-ui/react-bottom-navigation/>
* Bottom navigation
* Tabs

<https://developer.apple.com/design/human-interface-guidelines/toolbars#app-top>
* Toolbars
* Tab bars

<https://www.skyscanner.design/latest/components/accordion/web-sEshz9Z5>
+ Bottom navigation

## 検索したキーワード

* UI
* 部品
* component
* Tabs や toolbar
postfix+dovecot on Ubuntu 22.04LTS のOSユーザーから仮想ユーザーの切り替え

sasl認証をdovecotに任せている設定の場合。
OSユーザーだと、メールの認証は下記のとおりになるはず。
ID: ユーザー名
PASS: パスワード

これを仮想ユーザーに切り替える際に、/etc/dovecot/usersに
ユーザー名@ドメイン名:{PLAIN}パスワード

と書くよう記載しているサイトが多いが、その場合のメール認証は
ID: ユーザー名@ドメイン名
PASS: パスワード

にしないと認証失敗になる。IDに@以下が必要。
というかusersにそう書いたわけだし...
これに気づくのに半日かかった(T_T)
DBeaverがエラーを吐いたり起動できなくなったときの対処法

# DBeaverが起動できないときの対処法
## 背景
急にDBeaverがエラーを吐くようになり、エラーを無視して使用していたところ起動しなくなりました。

## 環境
* Ryzen5 5625U
* DDR4 64GB 3200Mhz
* Windows11 Home 22H2

## 解決策
設定ファイルが正常に保存されないことによるエラーのようです。
フォルダ削除することにより解決しました。

設定ファイルの場所
```
C:\Users\{ユーザー名}\AppData\Roaming\DBeaverData\workspace6
```
内の<font color="#ff0000">**「.metadata」**</font>フォルダを削除する。(削除するのが不安な場合はフォルダ名を変更してやれば大丈夫です。)

※ AppDataは隠しファイルのため、隠しファイルを表示する設定にしたほうが見つけやすいです。
[AWS]SecurityHubを導入したら最低限やっておきたい設定の自動化

# はじめに

SecurityHub、使っていますか？

AWS環境上にシステムを構築するにあたり、様々なセキュリティフレームワークに準拠しているかを管理できる便利なツールなのでAWSアカウントを開設したら是非有効にしたいサービスです。

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/what-is-securityhub.html

Organizationの統制化にあるアカウントであれば、CloudFormationStackSetsやAWS ServiceCatalogなどで実装することもできるかもしれませんが、

* terraformを常用しており、cloudformationに馴染みがない（学習コストを許容できない）。
* お客様所有の環境など、StackSetsやServiceCatalogを使ううまみがない。

などの理由でterraformで実装したいというケースもあるかもしれません。

本稿ではterraformでSecurityHubの有効化と、一緒にやっておきたい最低限のセキュリティ設定を自動で行いたいと思います。

# 設定すること

本稿では以下のサービスを有効化します。

* Config
* SecurityHub
* GuardDuty
* Inspector

SecufrityHubの標準は下記の二つを選択しています。
* Center for Internet Security (CIS) AWS Foundations Benchmark v1.4.0
* AWS Foundational Security Best Practices (FSBP) 標準

SecurityHubの標準って？という方は下記を参照してください。

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/standards-reference.html

上記の標準を有効化するとAWSアカウント内の各種設定状況がチェックされ、標準に準拠していないものが検出されます。

そこで、デフォルトの状態だと検出されてしまうであろうアカウントレベルの設定もまとめてterraformで対応してしまいます。
具体的には下表のSecurityHubコントロールとなります。

| ID | 説明 |
|:-|:-|
| IAM.7	 | IAM ユーザーのパスワードポリシーには、強力な設定が必要です |
| IAM.15 | IAM パスワードポリシーで、最小文字数の 14 文字かそれ以上が要求されていることを確認する |
| IAM.16 | IAM パスワードポリシーを確認して、パスワードの再利用を防ぐ |
| IAM.18 | AWS サポートでインシデントを管理するためのサポートロールが作成されていることを確認する |
| S3.1 | S3 ブロックパブリックアクセス設定を有効にする必要があります |
| EC2.7 | EBS のデフォルト暗号化を有効にする必要があります |

SecurityHubコントロールって？という方は下記を参照してください。

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-controls-reference.html

# 実装

https://github.com/sota-shimoyama/terraform-security_basic_configration/tree/main

上記リポジトリにコードを保存しています。
ご利用の環境に合わせてenvファイルを作成の上terraformを実行してください。

READMEにも使い方を記載していますが、不要なモジュールをコメントアウトすることで有効化したいサービス、適用したい設定を絞ることができます。

# おわりに

いかがでしたでしょうか。

「AWSアカウントのセキュリティを高めたいけど、何から始めたらいいかわからない」という方は、
まずSecurityHubを有効化してみることをおすすめします。

今回有効化した各種サービスもそれぞれに費用がかかります。
対象アカウントのユースケースに合わせて必要なサービスを取捨選択しつつ、上手にセキュリティを高めていきましょう。

※ 参考（各サービスの料金）

https://aws.amazon.com/jp/security-hub/pricing/

https://aws.amazon.com/jp/config/pricing/

https://aws.amazon.com/jp/guardduty/pricing/

https://aws.amazon.com/jp/inspector/pricing/
HTMLフォームタグのinputタグで使うname属性名って結局何？

# まとめ
HTMLフォームのinputタグで指定するnameは
「nameで指定した名前 = 値」
がリクエストパラメータとして送られる。
これはGETでリクエストパラメータで送り、URLを確認するとよくわかる。

## 経緯
~~~html
\<form method="POST" action="送り先アドレス"
 \<p>あなたの名前は？\</p>
  名前:\<input name="namae" type="text"/>
\</form>
~~~
このようなHTMLのフォームがあったとして、input属性の値は
どのような形で送られているか分からなくなったので調べてみた。

## 確認方法
POSTでは内部で処理が行われるため見た目では何が起きているか分かりにくいが
GETにするとURLの末尾にリクエストパラメータが表示されるので、どのような形でデータが送られているか分かるのでないかと考えた。

実際に送り方をGETに変え(method=GET)実行してみた。
テキスト欄にtanakaを入力して実行すると、URLの後半は
`...ファイル名.jsp?namae=tanaka`
と表示された。
これより、`name属性の名前=値`でリクエストパラメータが送られていることが分かる。
リクエストパラメータの値を取得するときはgetParameterメソッドを使うが、引数にname属性の名前を指定することも、これが分かっているとイメージしやすいと感じた。

Web等でinputタグを調べると、nameは部品の名前を指定すると書かれているが
言い換えれば「部品の名前=送りたい値」としてリクエストパラメータが送られると言える。
そして、値を取得したいときは部品の名前を指定する事もイメージが容易にできる。
mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e')

## エラー内容
`rails new`しようとしたところ次のエラーが発生。
```
$ rails new .
<internal:/Users/hoge/.rbenv/versions/3.2.0/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:148:in `require': dlopen(/Users/hoge/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/stringio-3.0.8/lib/stringio.bundle, 0x0009): tried: '/Users/hoge/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/stringio-3.0.8/lib/stringio.bundle' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e')), '/usr/local/lib/stringio.bundle' (no such file), '/usr/lib/stringio.bundle' (no such file) - /Users/hoge/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/stringio-3.0.8/lib/stringio.bundle (LoadError)
```
エラー内容から、arm64eアーキテクチャが必要なところx86_64で呼び出しされていることが原因だと判明。

## 解決方法
以下コマンドを実行
```
$ rbenv uninstall 3.2.0
$ arch -arm64e rbenv install 3.2.0
$ gem install bundler
$ gem install rails
```
arm64e向けのrubyをインストールすることでRubyとその関連のgemもarm64e向けにコンパイルされました。
再度`rails new`を実行しようとしたところうまくいきました。

## プラスの学び
### x86_64
現在広く使われるコンピュータのアーキテクチャであり64ビットのx86アーキテクチャの拡張版。「複雑な処理」を「少ない命令」で実行しようとする思想を持ち、高速な演算、互換性などが特徴。

### arm64e
ARM社が開発したCPUアーキテクチャの一つ。「単純な命令のみを備えて効率を向上させよう」という思想を持ち、スマホ・タブレット・サーバーなどに利用され、高いエネルギー効率と高速処理、セキュリティ向上などが特徴。

なんとなーくで学習してしまっていたのでCPUアーキテクチャの復習になりました！
こちらの記事で詳しく書いてらっしゃる方がいたので勉強になりました！
https://qiita.com/Lion_rion/items/bd17381031648fabaa81
自己紹介

はじめまして、puchankoと申します。
初めてのQiita投稿なので、まずは自己紹介から書いていこうと思います。

# 経歴
30代半ばの男性。(2023年現在)
職歴としては飲食店、ライブハウス、コールセンターなどを経験。
2021年に半年間ほど職業訓練校に通い、そこでJavaとPythonについて学ぶ。
その後、SES企業に就職。
現在はJava案件に参画中。

以上、めちゃくちゃざっくりとした経歴紹介となります。

# なぜQiitaを始めたのか？
30代半ばにしてITエンジニア歴1年ちょっとの私が、なぜ今更になってQiitaを投稿し始めたかについて軽く紹介する。
そもそも私がなぜITエンジニアに転職したかというと、正直言って「なんとなく」である。
今までの人生、それなりに色んな仕事をしてきて楽しく過ごしてきたが、貯金がそこまであるわけでもないし、手に職があるわけでもない。
「このままではヤバいな」いう漠然とした焦りを30代に突入してから徐々に感じてはいたが、特に何か行動を起こすわけでもなく過ごしてきた。
新型コロナウイルスが蔓延し、前職での仕事も不安定な状態となってきた頃、転職の相談をしにハローワークに行って職業訓練校を紹介してもらったという流れ。
「プログラマーって難しそう。でもできたらカッコよさそう。給料も良さそう。」と思っていたプログラミングにここで初めて出会った。
現在は無事にITエンジニアとしての職に就くことはできた。これで手に職もつけて給料も上がって安定した生活が送れる！ と思ったのも束の間。はっきり言って実務におけるIT現場は想像以上に辛くて苦しかった。
実務における業務要件とは、非常に膨大で広範囲に及び、複雑性が元から爆発してるような案件ばかりで、理解をするのに非常に多くの時間と労力を要した。
あと、めちゃくちゃ汚いソースコードは普通にたくさんあるし、汚いだけじゃなくて業務要件満たせてないのも普通にあるし、設計書も人によって書き方や表現が違ったり分かりづらいのも多いし、そもそも書いてることとやってることが違うときもあるし、テストの仕様書・エビデンスも人によって書き方が違ったり、前提条件が書かれてなくて何をテストしてるのか分からなかったり、現場のリーダーやマネージャなどの責任者とコミュニケーションが上手く図れなくて意思疎通ができなかったり…、挙げていくと本当にキリがない。
「このままではヤバいな」と、ITエンジニアになる前にも言ったはずの台詞をまた繰り返し、この状況を打開するためには自分が変わるしかないと思い、幅広い分野を勉強したり、個人開発をしたり、そういった個人的な活動を発信していけば「何か」変わるかもしれない、そういう思いで始めてみました。

QiitaやZennなどの技術系メディアには普段から大変お世話になっていると同時に、ここに投稿をしているエンジニアの方々は本当に優秀で凄いなぁ…と、自分とは別の世界の生き物だと勝手に認識していたのですが、もしかしたら私と同じように、30代を過ぎてからITエンジニアに転職したものの、仕事が思うようにできなかったり、酷い案件にアサインされて心を病んでしまったり、個人開発をしたいけど自分のスキル&知識不足で全然進まなかったり、などなど、さまざまな悩みを抱えている人もいるかもしれないと思い、まずは自分のことを何もかも曝け出してみようと思いました。

# これから
私はITエンジニアとしてのキャリアがまだまだ浅いので、分からないことだらけですが、その「分からないこと」をどんどん積極的に発信していこうと思います。
普段は主にJavaを扱うバックエンドエンジニアとして働いていますが、他の言語や技術ももっと習得したいので、自分が知らない未知の領域を学んでいこうと思います。
なので、分かる人からすれば「え、そんな簡単なことも知らないの？」「よくそのレベルでITエンジニアに転職できたな」と馬鹿にされるかもしれませんが、そんなことは気にせず自分のペースでやっていこうと思います。

今後の記事などで、誤りがあれば是非訂正のコメントをして欲しいですし、もっと良いやり方があればアドバイスもして欲しいです。
ただ、優しくお願いしますね。
では、よろしくお願いします。