OmniAICreator/Qiita-1.07M huggingface dataset:
アニメ「ダンジョン飯」から学ぶチーム再編時のマネジメント

2024年1月より放送開始の「ダンジョン飯」。
1/24現在ではまだ3話しか放映されていないのにも関わらず、個人的には1、2話を観るだけ（約1時間）でマネージャーがチームを作るとき、あるいは再編するときに気をつけるべきことが詰まっていたので取り上げる。

キーとなるのは1話でパーティーの新規参入者として登場する[「センシ」](https://dic.pixiv.net/a/%E3%82%BB%E3%83%B3%E3%82%B7)というドワーフ族のおっさん。彼がマネジメントを語る上でのキーマンとなっている。
ということで、彼を中心にパーティ（チーム）の再編時のマネジメントについて語ってみよう。

**※アニメのネタバレが間接的に含まれているので嫌いな方は読まずに閉じてください。**

<br /><br /><br /><br /><br />





## 空気を読まない

センシは空気を読まない。基本的に自分の欲望（調理）に忠実である。しかしながら知識は豊富だし、欲望を叶えるためには様々な方法で仲間と協力するし仲間を利用する。そのおかげでなんだかんだあっても素晴らしいダンジョン飯が出来上がる。
新しいチームのマネージャーも同じである。

マネージャーが変に空気を読んでしまうと、それが「チームの当たり前」になっていく。だから、マネージャーは基本的に空気を読まず思ったことや考えたこと、感じたことをストレートに伝えた方が良い。
プロダクトを成功させる、デリバリー速度を改善する、品質を向上させるなどなどマネージャーに与えられた目標は色々あるだろうが、それらを明確にチームに開示する必要がある。
何を達成ために何をやってもらうかということも大っぴらに会話して意識を共有する必要がある。
全ては美味しい飯にありつくために。ダンジョン飯。

## 役割を良い感じにする

2話でのセンシと[チルチャック](https://dic.pixiv.net/a/%E3%83%81%E3%83%AB%E3%83%81%E3%83%A3%E3%83%83%E3%82%AF)とのやり取りのとおり、チームには役割や権限、そして個人のパーソナルな範囲というものが存在する。
それには長い人生の道程で身についた当人の性格や経験に基づくものかもしれない。その場合は絶対に否定してはいけない。心理学の世界では性格はそう簡単に変えられない（他人のテコ入れ程度ではほぼ変わらない）と言われているので、ここで争っても意味がない。ダンジョン飯でもチルチャックが諦めているというかセンシの性格を受け入れている。その上で条件や守るべきことを共有し、お互いの認識共有をしよう。

また、長く同じチームメンバーで固定されている組織は「コンフォート・ゾーン」を無意識に作ってることもあり、新しいことに挑戦する、新しい仕組みを取り入れるというのに否定的意見が出やすくなっている場合がある。
幸いライオスのパーティはセンシが加入してもあまり役割が被ることがなくぶつかり合う場面が少ない。現実のチーム再編の際はこのあたりについて被りそうな部分あるいは被ってしまったと認識した部分は、当事者間またはチーム全体で素早く話し合いをして境界線を明確に作るのも良いかもしれない。
もちろん、境界線を承知の上で超える場面もあると思うので、その際は相手の領域侵犯の非礼を詫びるくらいの態度は示そう。（これについては次の章で詳細に述べる）

さらに、チームの人が増えたり減ったりすると新しい役割も発生する。これについても既知の部分の共有や作業の引き継ぎ、未知の部分の洗い出しや責任の所在の確認などをチームで行い、役割に対する新たな役割分担を作成していこう。

あとはお互いを信頼し、役割をこなすだけだ。煮えたぎった油を受けきったセンシのように。センシに言われるがまま料理に協力するチルチャックのように。チームが協力すればより良い仕事ができる。人も飯も変わらないのだ。ダンジョン飯。

## 相手を褒める・尊重する・感謝する

こちらも2話から。
マルシルが提案するマンドレイクの取り方は教科書通りのやり方であったが、近くに犬はいない、効率が悪いという感じに実践する前にチームに否定されている。
逆にセンシは長年の経験と実践的手法に従ってマンドレイクの収穫に成功している。
その後マルシルの（役に立ちたいという気持ちゆえの）暴走により叫びまくったマンドレイクを収穫できた際には、
実は叫ばせたほうがマンドレイクの味はまろやかになるということが判明した。
以上のように、チームでの活動には実践と知識のバランスが重要だ。どちらが良い・悪いというわけではなく、どちらの意見も尊重した上で知識なら実践を、実践なら検証をというふうに次のプロセスを検討しよう。
ライオスも劇中で言っていたように、メンバーには得手不得手が存在するのが常なので、それぞれの得意が良い感じに噛み合うようにするのもマネジメントの手法の1つである。
そして、新しい発見があったり助けられたりしたら「褒める」「感謝する」行動を取ろう。センシもしっかりとマルシルに対して言葉で感謝の意を述べている。これもまた重要。

「いただきます」「ごちそうさまでした」。人も飯も、感謝の言葉から始まり、感謝の言葉で終わる。ダンジョン飯。

---

最後に、ダンジョン飯はとてもマネジメントの勉強になるのだが、逆にバーンブレイバーンは話を聞かない部下をどうやって正しい方向に仕事させるかという方法を学ぶのに良いので、ぜひこちらも視聴していただきたい。
データベースを整理した

# 初めに

投稿一覧ページでそれぞれの投稿に紐付いているユーザ名や画像を表示できなかったので書きます。

# 問題

以下エラーに遭遇しました。

![スクリーンショット 2024-01-24 20.09.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536873/d6ec7692-41ee-d728-fef1-652a6d0f0b89.png)


# 解決方法

エラー文から推測して、この辺りを調査しました。

① Viewファイルの誤字脱字

② Postsコントローラーのindexアクション内でインスタントメソッドuserの定義忘れ

③ インスタントメソッドの理解不足

②まで調査して、インスタンスメソッドが何をしているのか理解できていなかったので復習しました。復習を終えて、③が原因ではないと分かりました。そこで、こちらの記事を参考にデータベース周りを調べました。

https://qiita.com/TeppeiMimachi/items/755639c775c72cb73ad9

全ての投稿データを取得して、id:1 の user_idがnilとid:2 のuser_idが1になっていることが分かりました。これは、開発の途中で投稿に紐ずくようにuser_idを追加したからです。なので、user_idが追加される前の投稿はnilとなっています。

```bash
rails console
posts = Post.all
id: 1,
  content: "Ruby",
  created_at: Wed, 17 Jan 2024 22:47:13.503984000 UTC +00:00,
  updated_at: Wed, 17 Jan 2024 22:47:13.503984000 UTC +00:00,
  user_id: nil>,

  id: 2,
  content: "JavaScript",
  created_at: Wed, 17 Jan 2024 22:50:54.265051000 UTC +00:00,
  updated_at: Wed, 17 Jan 2024 22:50:54.265051000 UTC +00:00,
  user_id: 1>,
```

nilのデータが含まれていることが原因ということが分かったので、1度データベースをリセットしましょう。リセットすると、解消されました。

```ruby
rails db:reset
```

# 終わりに

記事を参考にして分かったままにしないで言語化することが大切だと感じました。
【Python】hatchでPyPIの二要素認証を解決する

# `hatch`とは

[hatch](https://github.com/pypa/hatch)はPythonのプロジェクトマネージャーです。プロジェクト管理用の便利なコマンドが揃っているという長所と、検索すると`matplotlib`の引数の`hatch=`が引っ掛かってしまうという短所があります。
日本語の記事では[こちら](https://zenn.dev/mnagaa/articles/3a02ebc0431f36)など参考になります。

# PyPIの二要素認証

PyPIアカウントを二要素認証にしないとダメになりました。

https://blog.pypi.org/posts/2023-05-25-securing-pypi-with-2fa/

それ自体はいいんですが、トークンを`hatch`に教える必要があります。でないと`hatch publish`が使えなくなります (403エラーが出る)。

# どうすればよいか

以下のコマンドを叩きます。

```bash
$ hatch publish --user __token__
```

すると

```
Credentials:
```

みたいなのが求められるので、`pypi-*****`みたいなとても長いトークンをコピペすればOKです。

(ちなみにPowerShellでやったらペーストしても何も文字が増えず、ペーストが禁止されているのかと思って絶望しましたが、単に文字が表示されない仕様でした)
Kubernetes Podのライフサイクル

# はじめに

**Kubernetes** **Pod**のライフサイクルを理解することは、効果的なコンテナオーケストレーションのために不可欠です。このブログ投稿では、**Pod**が経るさまざまな状態と、それらの作成に関連する条件について掘り下げてみます。この知識は、**Kubernetes**ワークロードの管理とトラブルシューティングに不可欠です。

## Podのライフサイクル
ここで議論するPodのライフサイクルの複数のタイプの状態があります。

**1. Pending（保留中）:** Podが作成されると、MasterノードはPodを作成するノードを割り当てるために保留状態を経る必要があります。Podは、CPU、メモリ、およびストレージなどの必要なリソースが全て割り当てられるまで、保留状態にとどまります。

**2. Running（実行中）:** ポッドがノードにスケジュールされると、実行状態に入ります。実行状態に入ると、ポッド内のコンテナは、マニフェストファイルで指定されたタスクを作成および実行します。

**3. Succeeded（成功）:** ポッドがタスクを完了した場合、ポッドはSucceeded状態に入り、その後終了します。

**4. Failed（失敗）:** ポッドが作成されようとしているが、何らかの問題によりポッドが作成されず、Failed状態が表示されると、ファイルの作成者によって修正が必要な構成の問題が発生しています。

**5. CrashLoopBackOff:** これはFailed状態の高度な状態であり、コンテナがクラッシュして再起動します。この問題を修正するには、ファイルの作成者がマニフェストファイルを確認する必要があります。

**6. Unknown（不明）:** 一部の場合、Kubernetesはポッドを作成するためのノードとの接続を失う可能性があり、特定のポッドの不明な状態が表示されます。

**7. Termination（終了）:** ポッドが利用できなくなると、終了プロセスに入ります。ポッドが削除されると、同じポッドは再起動できず、Kubernetesクラスタ全体から削除されます。

Podの作成時に発生するいくつかの条件があります:

- **Initialized（初期化済み）:** この条件は、すべての初期化コンテナが正常に開始されたかどうかを示します。ステータスがfalseの場合、初期化コンテナが開始されていないことを意味します。

- **Ready（利用可能）:** この条件は、ポッドが利用可能であることを示します。

- **ContainersReady（コンテナ利用可能）:** 名前が示すように、ポッド内のコンテナが利用可能であれば、ステータスはTrueになります。

- **PodScheduled（ポッドスケジュール済み）:** この条件は、ポッドがノードにスケジュールされたことを示します。


```
kubectl get pods
```

<iframe width="1062" height="606" src="https://www.youtube.com/embed/337IBAS_izs" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

どんなポッドを作成し、次のコマンドを実行してそのポッドを説明すると:

```
kubectl describe pod <pod-name>
```

次のようなステータスが表示されます。ポッドはスケジュールされていますが、他のことは進行中ですので完了していません。

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620161/32219b9e-8ddc-9327-2261-4b0b6473d5af.png)


数秒後、同じポッドを再度説明すると、すべてが完璧で適切に構成されていることがわかります。

![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620161/21dd7d09-0019-42c1-2544-7a35095b93a3.png)


## 結論

Kubernetes Podのライフサイクルを管理し、その状態と条件を理解することは、コンテナ化されたアプリケーションのスムーズな動作を確保するために基本的です。これらの側面をモニタリングおよびトラブルシューティングすることで、健全なKubernetesクラスタを維持し、ユーザーに信頼性の高いサービスを提供できます。
インスタンスタイプをm5aからm6a(6世代)へ変更する際の注意点

インスタンスタイプを変更した際に、変更後インスタンスに接続できなくなってしまった。
m5aからm6aに変更する予定の人、やってみて同事象にハマった人の参考になれば。
と言ってもおそらく、6世代インスタンスに変更する際は共通して気を付ける必要がある。


## やりたかったこと
EC2のインスタンスタイプをm5aからm6aに上げたい。

## 起こったこと
インスタンスタイプ変更は正常に完了。
完了後ヘルスチェックに失敗、RDPにて接続できない。

## 調査
スクリーンショットでイメージを出すとログインの画面となっている。
→そのため、起動は成功している。
サポートを起票したところ、ENAドライバーのバージョンが古いとElastic Network Interface のアタッチメントに失敗するケースがある旨回答。

## 原因
信じるべきは、やはりサポート。
Elastic Network Adapter (ENA)のバージョンが古かったため、アタッチに失敗していた。
失敗したイスタンスのENAバージョン：1.5
推奨のENAバージョン：2.0以上

2018年以前に作成したインスタンスで作成時からENAドライバーのバージョンを上げていなかった。(気にしてもいなかった、が表現としては正しいか・・・)

## 対応の手順(Windows)
#### 1.ローカル管理者でログイン
PowerShellを開く。
#### 2.Powershellのバージョンを確認
```
$PSVersionTablee
```
PSVersionが5.0以上であることを確認。　
古かったら、ブラウザベースでやろう！3.0だと手順5のコマンドがなくて詰みます。
#### 3.ENAのバージョンを確認する。
コマンド
```
Get-WmiObject Win32_PnPSignedDriver| select devicename, driverversion | where {$_.devicename -like "*Amazon Elastic Network*"}
```
出力例
```
devicename   driverversion
----------        -------------
Amazon Elastic Network Adapter 1.5.0.0
```
2.0未満であることを確認。⇒2.0以上なのであれば、別の原因。
#### 4.最新のドライバーパッケージをダウンロード。
```
invoke-webrequest https://ec2-windows-drivers-downloads.s3.amazonaws.com/ENA/Latest/AwsEnaNetworkDriver.zip -outfile $env:USERPROFILE\AwsEnaNetworkDriver.zip
```
#### 5.Zipファイルになっているドライバーパッケージを解凍
```
expand-archive $env:userprofile\AwsEnaNetworkDriver.zip -DestinationPath $env:userprofile\AwsEnaNetworkDriver
```
#### 6.ディレクトリを移動
```
cd AwsEnaNetworkDriver
```
#### 7.インストーラーを実行
```
.\install.ps1
```
再起動されたことを確認し、インスタンスタイプを変更する。
## 反省
インスタンスタイプを変更する場合は、プロセッサーの互換性以外にもドキュメントを確認する。

## 公式の参考情報
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/enhanced-networking-ena.html#ena-adapter-driver-install-upgrade-win

https://repost.aws/ja/knowledge-center/migrate-to-gen6-ec2-instance
【GitHub】コミット名を変更する一番簡単な方法

## 概要
Githubでコミット名を後から変更する方法を紹介します。
「GitHub コミット名 変更」で検索するとrebaseしてeditする方法が出てきますが、それよりも簡単な方法です。

:::note warn
注意
この記事は新卒エンジニアが執筆しています。
そのため内容に間違いや不備がある場合があります。
もし間違いを発見しましたら、どんどん指摘していただけると幸いです。
:::

## やり方
`rebase`したのちにコミットに`reword`を指定します。
詳しく解説します。
### 1. `rebase -i`を実行する
まずは`rebase -i`を実行します。
``` bash
git rebase -i HEAD~5 // HEADから5つ前のコミットまで
```
実行すると以下のような画面になると思います。
``` 
pick aca1de2 commit1
pick bfh2ea1 commmmmit2 // このコミットを変更したい
pick 1abef2e commit3 

//# Commands:
//# p, pick <commit> = use commit
//# r, reword <commit> = use commit, but edit the commit message
//# e, edit <commit> = use commit, but stop for amending
//# s, squash <commit> = use commit, but meld into previous commit
//# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
//#                    commit's log message, unless -C is used, in which case
//#                    keep only this commit's message; -c is same as -C but
//#                    opens the editor
//# x, exec <command> = run command (the rest of the line) using shell
//# b, break = stop here (continue rebase later with 'git rebase --continue')
//# d, drop <commit> = remove commit
//# l, label <label> = label current HEAD with a name
//# t, reset <label> = reset HEAD to a label
//# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
//# .       create a merge commit using the original merge commit's
//# .       message (or the oneline, if no original merge commit was
//# .       specified); use -c <commit> to reword the commit message
```

## 2. 変更したいコミットに`reword`を指定する
次に変更したいコミットに`reword`を指定します。
``` 
pick aca1de2 commit1
reword bfh2ea1 commmmmit2 // このコミットを変更したい
pick 1abef2e commit3 
```
そして`:wq`で終了すると、以下のような画面になります。
``` bash
commmmmit2

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# ..........
```
そこで正しいコミット名に修正して、保存してください。
```
commit2

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# ..........
```

ログを確認すると、コミット名が修正されていると思います。
``` bash
git log --oneline
```
``` bash
aca1de2 commit1
bfh2ea1 commit2 
1abef2e commit3 
```

## まとめ
コミット名を変更したいときは、`rebase`して`reword`を指定しましょう
nice

```
NICE(1)                                                                                         User Commands                                                                                         NICE(1)



NAME
       nice - run a program with modified scheduling priority

SYNOPSIS
       nice [OPTION] [COMMAND [ARG]...]

DESCRIPTION
       Run  COMMAND  with  an adjusted niceness, which affects process scheduling.  With no COMMAND, print the current niceness.  Niceness values range from -20 (most favorable to the process) to 19 (least
       favorable to the process).

       Mandatory arguments to long options are mandatory for short options too.

       -n, --adjustment=N
              add integer N to the niceness (default 10)

       --help display this help and exit

       --version
              output version information and exit

       NOTE: your shell may have its own version of nice, which usually supersedes the version described here.  Please refer to your shell's documentation for details about the options it supports.

       GNU coreutils online help: <http://www.gnu.org/software/coreutils/> Report nice translation bugs to <http://translationproject.org/team/>

AUTHOR
       Written by David MacKenzie.

COPYRIGHT
       Copyright © 2013 Free Software Foundation, Inc.  License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
       This is free software: you are free to change and redistribute it.  There is NO WARRANTY, to the extent permitted by law.

SEE ALSO
       nice(2), renice(1)

       The full documentation for nice is maintained as a Texinfo manual.  If the info and nice programs are properly installed at your site, the command

              info coreutils 'nice invocation'

       should give you access to the complete manual.



GNU coreutils 8.22                                                                              November 2020                                                                                         NICE(1)
```
ps -el

```
[linuxstudy@xxxx ~]$ ps -el | head -6
F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0      1      0  0  80   0 - 32102 ep_pol ?        00:00:09 systemd
1 S     0      2      0  0  80   0 -     0 kthrea ?        00:00:00 kthreadd
1 S     0      4      2  0  60 -20 -     0 worker ?        00:00:00 kworker/0:0H
1 S     0      6      2  0  80   0 -     0 smpboo ?        00:00:04 ksoftirqd/0
1 S     0      7      2  0 -40   - -     0 smpboo ?        00:00:00 migration/0
[linuxstudy@xxxx ~]$ ps -el | tail -6
1 S     0  15770      2  0  80   0 -     0 worker ?        00:00:00 kworker/u256:0
1 S     0  15812      2  0  80   0 -     0 worker ?        00:00:00 kworker/0:0
1 S     0  15835      2  0  80   0 -     0 worker ?        00:00:00 kworker/0:3
0 S     0  15843    901  0  80   0 - 27014 hrtime ?        00:00:00 sleep
0 R  1000  15870   3076  0  80   0 - 38332 -      pts/0    00:00:00 ps
0 S  1000  15871   3076  0  80   0 - 27088 pipe_w pts/0    00:00:00 tail
```
各列の意味
```
       f           F         flags associated with the process, see the
                             PROCESS FLAGS section.  (alias
                             flag, flags).
PROCESS FLAGS
       The sum of these values is displayed in the "F" column, which is
       provided by the flags output specifier:

               1    forked but didn't exec
               4    used super-user privileges

       c           C         processor utilization. Currently, this is
                             the integer value of the percent usage
                             over the lifetime of the process.  (see
                             %cpu).
       pri         PRI       priority of the process.  Higher number
                             means lower priority.
       ni          NI        nice value. This ranges from 19 (nicest)
                             to -20 (not nice to others), see nice(1).
                             (alias nice).
       sz          SZ        size in physical pages of the core image
                             of the process.  This includes text, data,
                             and stack space.  Device mappings are
                             currently excluded; this is subject to
                             change.  See vsz and rss.
       nwchan      WCHAN     address of the kernel function where the
                             process is sleeping (use wchan if you want
                             the kernel function name).  Running tasks
                             will display a dash ('-') in this column.
```
Experience Bali Bliss: Yoga Teacher Training in Bali!

![class03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3683486/8a226755-6d6e-2d5a-b108-b34181d3e5f5.jpeg)

Bali is a charming place, known for its peaceful scenery and spiritual ambiance. Yoga seekers always find ideal backdrops for deep learning and growth. This is where Bali comes to the top of the list. There are several yoga schools available for this purpose. You can join yoga teacher training in Bali.

Yoga Teacher Training Programs: Experience Bali Bliss-

Immerse in Balinese Yoga Traditions- When it comes to yoga teacher training, Bali offers amazing settings. It combines the ancient wisdom with modern practices. This transformative experience cannot be overlooked as your yoga programs are led by seasoned yoga instructors. They are deeply rooted in Balinese culture. Embrace traditional yoga philosophies with meditation and pranayama methods.

The Appeal of Bali's Lovely Serenity- Imagine your yoga training amidst the wonderful backdrops of Bali. From green rice terraces in Ubud to the perfect beaches of Bali- witness the idyllic settings and enjoy your yoga practice. This ideal setting can help you control your mind, body and spirit.

Growth in a Spiritual Haven- Bali’s beauty isn’t only about its natural beauty. You can feel a spiritual ambiance. Yoga teacher training programs promote personal growth and inner discovery. You just need to understand the roots of yoga and explore its spiritual aspects. In addition, do not forget to witness the Balinese rituals and ceremonies that will give you a memorable experience.

Selecting The Best Yoga Teacher Training In Bali -

There are many yoga retreat centers and yoga schools in Bali. They may offer unique specialization programs. This is where you do your research broadly and make sure that it suits your expectations. Some factors like location, accommodation, curriculum, faculty expertise and other facilities should be considered. 

Tailoring Your Yoga Journey- Choose yoga programs for the best training experience. It should suit your expertise and interest. You can choose from 100-hour, 200-hour, 300-hour and 500-hour yoga teacher training courses. These courses will meet your aspirations and skill levels. 

Bali is a heaven for aspiring yogis. It gives an enriching experience. All you need to find a reliable yoga school that offers comprehensive range of yoga courses. Join yoga teacher training in Bali Yoga Center Ubud. Our Yoga center offers affordable yoga teacher training and retreats as well as classes for practitioners of all levels. Explore our comprehensive training program, expert instructors, and transformative retreats. Visit https://baliyogacenter.com/ today!
【Go】JWT認証をGinで必要最低限の実装をした

## やりたいこと
Ginでユーザーログイン機能を実装し、ログインユーザーだけがアクセス可能なエンドポイントをJWT認証を使って実装したい。

## JWT認証の仕組み
### JWTとは
### JWT認証の仕組み

## Ginで実装してみる

### ```main.go```
```go:main.go
import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

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

	r.POST("/login", loginHandler)

	authGroup := r.Group("/auth")
	authGroup.Use(authMiddleware)
	authGroup.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "you are authorized"})
	})

	r.Run(":8080")
}
```

- ```POST``` ```/login```：ログイン時にアクセスするエンドポイント
- ```GET``` ```/auth```：ログインユーザーしかアクセスできない

```/auth```が付くエンドポイントをグループ化し、middlewareを用いて、JWT認証できたユーザーのみアクセスできるようにする。

### ```User```構造体を定義
```go
type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

var validUser = User{
	Username: "test",
	Password: "testpass",
}
```

### ```loginHandler```
```go
func loginHandler(c *gin.Context) {

	var inputUser User

	// リクエストからユーザー情報を取得
	if err := c.BindJSON(&inputUser); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// ユーザー情報の検証
	if inputUser.Username != validUser.Username || inputUser.Password != validUser.Password {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user"})
		return
	}

	// トークンの発行（ヘッダー・ペイロード）
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"username": inputUser.Username,
		"exp":      time.Now().Add(time.Hour * 24).Unix(),
	})
	tokenString, err := token.SignedString([]byte(SECRET_KEY))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "error signing token"})
		return
	}

	// ヘッダーにトークンをセット
	c.Header("Authorization", tokenString)
	c.JSON(http.StatusOK, gin.H{"message": "login success"})
}
```
リクエストBodyから```User```構造体へバインドし、```Username```と```Password```が一致する登録ユーザーが存在するかを検証します。今回は面倒なのでDBを使わずグローバル変数で定義しています。

その後JWTトークンを発行し、HTTP Headerの```Authorization```にセットしてレスポンスを返します。

```go
const SECRET_KEY = "SECRET"
```

署名に使う秘密鍵はこんな感じで定義しておきます。

### ```authMiddleware```
```go:
func authMiddleware(c *gin.Context) {
	// Authorizationヘッダーからトークンを取得
	tokenString := c.GetHeader("Authorization")

	// トークンの検証
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return []byte(SECRET_KEY), nil
	})
	if err != nil || !token.Valid {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
		c.Abort()
		return
	}

	c.Next()
}
```

リクエストのHTTP Headerの```Authorization```からJWTトークンを取得します。
その後、```jwt.Parse```を用いてJWTトークンを検証します。ここのミソは***DBにアクセスしてユーザー情報を照合する必要がないこと***だと思います。JWTのシグネチャをデコードしてペイロードと一致すれば有効なトークンであることが保証されているのが理由です。

## 参考
https://developer.mamezou-tech.com/blogs/2022/12/08/jwt-auth/
[Android]マイナンバーカードの読み込みでjava.lang.SecurityException: Permission Denial: Tag ( ID: XX XX XX XX ) is out of date

## はじめに
AndroidでマイナンバーカードをNFCで読み込んだときに出たエラーの対応メモ

## エラー内容
Androidでマイナンバーカードを読み込んだときにこのエラーが発生しました。

```
e = {SecurityException@30494} "java.lang.SecurityException: Permission Denial: Tag ( ID: XX XX XX XX ) is out of date"
 backtrace = {Object[19]@30503} 
 cause = {SecurityException@30494} "java.lang.SecurityException: Permission Denial: Tag ( ID: XX XX XX XX ) is out of date"
 detailMessage = "Permission Denial: Tag ( ID: XX XX XX XX ) is out of date"
 stackTrace = {StackTraceElement[18]@30507} 
 suppressedExceptions = {Collections$EmptyList@30505}  size = 0
 shadow$_klass_ = {Class@3092} "class java.lang.SecurityException"
 shadow$_monitor_ = 0
```

## 原因
実行した端末のOSがAndroid13で実行するとエラーになる様子（他のバージョンで試してないので本当かどうか不明）
https://stackoverflow.com/questions/76428518/securityexception-permission-denial-with-android-13-when-working-with-nfc

## 対応
targetSDKバージョンが31だったためとりあえず34に変更したらエラーが改善されました。

## さいごに
バージョンによるエラーなどはAndroidはいまだに結構あるなと思うので複数端末で実行してエラー原因を特定することが大切
AtCoder Beginner Contest 336 D 考察

ABC336 D の考察していきます。
https://atcoder.jp/contests/abc336/tasks/abc336_d

ピラミッド数列を作る問題。ピラミッド数列は、長さ `(2k−1)`の数列であって各項の値が順に `1,2,…,k−1,k,k−1,…,2,1`であるようなもの。

問題文に色々条件が書いてあるけど、要はピラミッド数列を作ればいい。Haskellだとこういうの簡単にできる。

まずは、0から初めてscanlで1つづつ値を加算していく。入力値と加算した値を比較して、入力値の方が低い場合、ピラミッドの最大値を超えたと考えられるので小さい方を選択する。
また、0は不要になるので、[postscanl](https://hoogle.haskell.org/?hoogle=postscanl)を使う。scanlの後tailしてもよい。
VUでコードにするとこんな感じ
```haskell
 let ls = VU.postscanl (min . succ) 0 as
```
これを試しで動かすとこうなる
```haskell
 ghci> let as = VU.fromList [2, 2, 3, 1, 1]
 ghci> print $ VU.postscanl (min . succ) 0 as
 [1.0,2.0,3.0,1.0,1.0]
```
但し、以下のように単調増加する配列だとうまくいかない(ピラミッド数列にならないため)
```haskell
 ghci> let as = VU.fromList [2, 2, 3, 4, 5]
 ghci> print $ VU.postscanl (min . succ) 0 as
 [1.0,2.0,3.0,4.0,5.0]
```
そこで、リストの右側からも同じ計算をして、zipWithして最小値を取る。
リストの右側から計算するとこのような感じ。
```haskell
 let rs = VU.postscanr (flip (min . succ)) 0 as
```
これで計算するとこんな感じ
```haskell
 ghci> print $ VU.scanr (flip (min . succ)) 0 as
 [2.0,2.0,2.0,1.0,1.0,0.0]
 ghci> print $ VU.postscanr (flip (min . succ)) 0 as
 [2.0,2.0,2.0,1.0,1.0]
```
zipWithを使って最小値をとるとこう
```haskell
  VU.zipWith min ls rs
```
計算するとこう
```haskell
 ghci> let ls = VU.postscanl (min . succ) 0 as
 ghci> let rs = VU.postscanr (flip (min . succ)) 0 as
 ghci> print $ VU.zipWith min ls rs
 [1.0,2.0,2.0,1.0,1.0]
```
で、出力結果を見るとわかるけどこれはピラミッド数列にはなってない。
でもこの問題は最大値を求める問題なので、特に問題はない。
コードの全体像はこんな感じ
```haskell
 main = do
   n <- readLn @Int
   as <- VU.unfoldrN n (BS.readInt . BSdropWhile isSpace) <$> BS.getLine
   let ls = VU.postscanl (min . succ) 0 as
   let rs = VU.postscanr (flip (min . succ)) 0 as
   print $ VU.maximum $ VU.zipWith min ls rs
```
※unfoldrNはhttps://hoogle.haskell.org/?hoogle=unfoldrN を見てね。unfoldrをn個分やるみたいなノリ

これでACになった。
https://atcoder.jp/contests/abc336/submissions/49410918
【エラー】Ports are not available: ~ already in use 対処法

<br>
PostgreSQLを使用して出たエラーです。
<br>
<br>

下記のエラーが出ました。
```
Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:5432 -> 0.0.0.0:0: listen tcp 0.0.0.0:5432: bind: address already in use
```


<br>
<br>
ポート番号5432は使われていると出たので、何を開いているのか確認してみました。

```
lsof -i :5432
```
何も出てきません。
<br>
<br>
スーパーユーザ権限でリスニング状態のネットワーク接続（サーバーが接続を待っているポートなど）を表示

```
sudo lsof -i -P | grep "LISTEN"
```
<br>
<br>

以下の出力から、PostgreSQLデータベースがポート5432でリスニングしており、外部からの接続を待ち受けている状態を示しています。
```
postgres   584          postgres    8u  IPv6 000000000000000000      0t0    TCP *:5432 (LISTEN)
postgres   584          postgres    9u  IPv4 000000000000000000      0t0    TCP *:5432 (LISTEN)
```
<br>
<br>

ポート番号5432で立ち上げたいため、5432で立ち上がっているPID　584のものを終了させます。
```
sudo kill 584
```
<br>
<br>

立ち上げができました🎉
AtCoder Beginner Contest 337 D 考察

今回から、D問題も少しづつ解いていこうと思ってます。（他の人の回答を参考にしながらですが）
せっかくなので、Qiitaでも考察をまとめていきます。

- [問題](https://atcoder.jp/contests/abc337/tasks/abc337_d)
- [参考になりそうな回答](https://atcoder.jp/contests/abc337/submissions/49558947)
- [解説](https://atcoder.jp/contests/abc337/editorial/9139)

累積和の応用問題。

`.`の数と`x`の数をあらかじめ累積和で計算しておき、最小手数で問題の回答を得るようにする。ポイントは[ここ](https://atcoder.jp/contests/abc337/editorial/9139#:~:text=具体的に,で済みます%E3%80%82)。

ある縦横の範囲 `[i,i+K−1]`に`x`が無いとき、`.`の個数が求める手数となる。
この時`x`の個数は
```math
X_{i+K−1} ​− X_{i−1}
```
​`.`の個数は
```math
D_{i+K−1} ​− D_{i−1}
```

で求められる。

つまり、`[i, i+K-1]`の範囲で `x`の個数が0個となっている時の`.`の最小値を求めれば良い。

まずは`x`, `.`の累積和を求める処理を書く。

`(X, D)`の形でタプルを持たせていることがポイントになる。
```haskell
 accum :: String -> [(Int, Int)]
 accum = scanl f (0, 0)
   where
     f (d, c) '.' = (succ d, c)
     f (d, c) 'x' = (d, succ c)
     f (d, c) _ = (d, c)
```

ある範囲の`x`, `.` の個数を求める処理は以下
```haskell
 count :: (Int,Int) -> (Int,Int) -> (Int,Int)
 count (x1, y1) (x2, y2) = (x1 - x2, y1 - y2)
```

`[i, i+K-1]`の個数を座標毎に求めるとこうなる。`x`の個数が0出ないといけないので`filter((==0) . snd)`して`concatMap`で繋げている。座標は0から始まるので、以下のように計算している。
```math
X_{i+K} ​− X_i
```
```math
D_{i+K} ​− D_i
```
また、`[i, i+K]`の範囲でスライドしていくので、座標の区間を`[0, W]`とすると、計算する区間は`[0, W-K]`となる。ある行もしくは列ごとの計算を書くとこのようになる。
```haskell
 select :: Int -> Int -> [Array] -> [Int]
 select w k arrs =
   map fst $
     concatMap (filter ((== 0) . snd) . \arr -> [count (arr A.! (i + k)) (arr A.! i) | i <- [0 .. w - k]]) arrs
```
少々複雑なので一つづつ解説すると、まず以下の無名関数で、`[0, w-k]`に対して`count`を呼び出している。
```haskell
 \arr -> [count (arr A.! (i + k)) (arr A.! i) | i <- [0 .. w - k]]
```
`arr A.! (i + k)`から`arr A.! i`の差分を取っているので、具体的には以下のような計算になる
```math
(X_{i+k} - X_i, D_{i_k} - D_i)
```
一つ目の要素が`.`の数（つまり変換手数）で、2つ目の要素がが`x`の個数になる。
そのため、これを`(filter ((== 0) . snd)`でfilterし、問題の条件に合致する要素だけ抽出する。抽出した結果の一つ目の要素が変換手数になるので、`map fst`で手数だけのリストにする。

これを横縦（行列）で計算するので、
行は
code:haskell
   let rows = map (A.listArray (0, w) . accum) ss :: [Array]
   let rowCands = select w k rows
列は`transpose`して
```haskell
   let cols = map (A.listArray (0, h) . accum) (transpose ss) :: [Array]
   let colCands = select h k cols
```
これで求める手数のリストを取得できるので、最後は連結して最小値を取得すれば求める解が得られる。
```haskell
  let anss = rowCands ++ colCands
  if null anss
    then print (-1)
    else print $ minimum anss
```
計算量は、行もしくは列の累計和とselectで　`O(HW)`となること、これ以上計算量の大きい処理がないことから、この計算量となる。(`transpose`の計算量も`O(HW)`)
商品一覧表示機能の実装（ActiveHashの使用）

# はじめに
プログラミング初心者です。
自分のアウトプットのため投稿しています。
間違っているところがあれば、指摘していただけますとありがたいです。
# 商品一覧出品機能の実装
サーバーに保存されているデータをビューに反映させます。
今回はActiveHashを利用したフリマアプリですが、いつもとそんなに変わりません。
[![Image from Gyazo](https://i.gyazo.com/2d6ace9a6e89bb517a40ca1c84298253.png)](https://gyazo.com/2d6ace9a6e89bb517a40ca1c84298253)
ActiveHashを使用している場合、このままだと
[![Image from Gyazo](https://i.gyazo.com/f6baa88ecbdb0710108bdc9b41e7cf74.png)](https://gyazo.com/f6baa88ecbdb0710108bdc9b41e7cf74)
このような表示になってしまうので、nameをつけます。
[![Image from Gyazo](https://i.gyazo.com/9da410c19f8c823073a2714aa8df419d.png)](https://gyazo.com/9da410c19f8c823073a2714aa8df419d)

[![Image from Gyazo](https://i.gyazo.com/a8bed4ea2ae9fc87ee2ec72970237853.png)](https://gyazo.com/a8bed4ea2ae9fc87ee2ec72970237853)
ちゃんと表示されました！
### ちなみに
[![Image from Gyazo](https://i.gyazo.com/806656d8864fa420885a9eebe1b91875.png)](https://gyazo.com/806656d8864fa420885a9eebe1b91875)
モデルにこのように記述してもActiveHashの名前がちゃんと出てきます。

今回は以上です。
【即解決】LinuxとWindowsをデュアルブートさせたら時刻がずれる現象の解決方法

# はじめに
LinuxとWindowsをデュアルブートさせた際に、Linuxを使ってからWindowsを起動させると、時刻が数時間単位でずれていることはないだろうか。

数秒程度ならば、少なくとも日常使いにおいてはある程度許容できるが、数時間単位のずれとなるとかなりの支障になることは明らかである。

本記事ではそのような現象を解決するための具体的な方法と、根本の原因について解説する。

# 解決方法
結論から述べると、Linux側で以下のコマンドを実行することで解消する。

```
sudo timedatectl set-local-rtc 1
```

# 時刻がずれる原因
LinuxとWindowsをデュアルブートさせた際に時刻がずれる原因としては、両者それぞれのシステムクロックによるハードウェアクロックの解釈方法が異なるためである。

## ハードウェアクロックとシステムクロックについて

ハードウェアクロックとは、パソコンの集積回路上に搭載されている時計のことである。時刻情報に関してはCMOSに保存されている。一方のシステムクロックとは、OSのカーネルが管理している時計のことである。

ハードウェアクロックはコンピュータの電源を切っても、マザーボード上にある電池によって動作しているため、時刻情報が常に更新されている。しかしシステムクロックは主記憶装置上で時刻を管理しているため、コンピュータの電源を切るとその時刻情報を保持できずに失ってしまう。そこでOSの起動時にハードウェアクロックの情報をシステムクロックに反映させることで、時刻情報を取得している。

そして我々がディスプレイ上で見る時刻情報というのは、まさにそのシステムクロックから取得した時刻情報である。
## LinuxとWindowsで異なるハードウェアクロックの解釈方法
LinuxとWIndowsではシステムクロックによるハードウェアクロックの解釈方法が異なっており、それが今回のタイトルにもなっているデュアルブート時に発生する時刻ずれの原因になっている。

Linuxの場合はOSの起動時に、UTC（いわゆるイギリスでの時刻）をNTPサーバから取得し、その時刻情報をハードウェアクロックに設定している。その後システムクロックは、ハードウェアクロックから取得した時刻情報はUTCと解釈しているため、その時刻情報をローカルタイムに合わせて調整する。一方Windowsの場合は、OSの起動時にハードウェアクロックに設定する時刻情報はローカルタイムであるため、システムクロックはその時刻情報をローカルタイムと解釈して、そのままの値で取得したものを設定している。

![システムクロック＿ハードウェアクロック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642100/c1d47257-e80f-5d0b-6a9f-5263bb069724.png)


## デュアルブートさせていた場合
今回はローカルタイムに日本時間を設定していることを前提に話す。

デュアルブートさせていた場合、Linuxを起動させると上記の仕組みにしたがって、ハードウェアクロックはUTCを設定する。そしてシステムクロックはその時刻情報を基に、ローカルタイムに合わせて調整をする。ローカルタイムが日本時間に設定されている場合は+9hして調整する。その後Linuxを終了させてWindowsを起動した場合、Windowsのシステムクロックは時刻情報を得るために、ハードウェアクロックの時刻情報を取得する。

Windowsの場合はハードウェアクロックの時刻情報 = ローカルタイムと解釈しているため、そのままの時刻情報をシステムクロックに設定する。しかし先ほどLinuxを起動した際に、ハードウェアクロックには日本の時刻から-9hずれているUTCが設定されている（両者OSが使っているハードウェアクロックは同一のもの）。つまりこのとき、ハードウェアクロックの時刻情報をそのまま反映させたWIndowsのシステムクロックの時刻情報は、ローカルタイムから-9hずれたものになってしまっているのだ。これがLinuxとWindowsをデュアルブートさせたときに発生する時刻ずれの原因である。

# 解決方法
以上の仕組みを踏まえると、解決方法としては以下の2つのやり方が思いつく。

- Linux側でハードウェアクロックに設定する時刻情報をローカルタイムのものにする。
- Windows側でハードウェアクロックに設定する時刻情報をUTCのものにする。

この2つのうち前者のほうが比較的お手軽にできるため、本記事では前者のやり方を採用する。

後者のやり方を採用した場合はレジストリの編集が必要となり、より複雑な作業が必要になるため、あまりおすすめしない。

Linux側でハードウェアクロックにローカルタイムを設定させる方法としては、冒頭でも紹介した以下のコマンドを実行することである。

```
sudo timedatectl set-local-rtc 1
```

このコマンド文の意味を解説すると

- timedatectl
時計やタイムゾーンを設定するコマンド
- set-local-rtc 1
RTC（いわゆるハードウェアクロックのこと）をローカルタイムに設定するか否か。"set-local-rtc  \<bool>"の"\<bool>"の部分が0の場合は、ハードウェアクロックにUTCを、1の場合はローカルタイムを設定する。

よってこのコマンドを実行することで、Linux側でハードウェアクロックにローカルタイムを設定できる。

その後Linuxを終了させWindowsを起動しても、Windows側の時刻がずれる現象は解消されているはずだ。

# 終わりに
本記事ではLinuxとWindowsをデュアルブートさせたときに発生する時刻がずれる現象への解決方法と、その原因について解説した。

本記事で解説した解決方法などを実践しない限りは解消されない現象であることから、デュアルブート後にほとんどの人たちが遭遇する現象であると思われる。

この記事を読んで救われた読者が一人でも増えれば、筆者としてはとても嬉しい限りである。
ファイル名を変更する場合はgit mvコマンドを使おう

※この記事は僕がぶち当たった問題をとりあえずChatGPTくんに丸投げしてライティングしてもらったものです。

Gitを使用している際にファイルの名前を変更する必要がある場面はよくあります。
ファイル名の変更を適切に行うためには、git mvコマンドを使用すると便利です。
この記事では、git mvコマンドの基本的な使い方と、その利点について説明します。

# 1. git mvコマンドの基本
git mvコマンドは、ファイルの移動や名前の変更を行うためのコマンドです。基本的な構文は以下の通りです。

```bash
git mv <旧ファイル名> <新ファイル名>
```
例えば、example.txtというファイルをnew_example.txtにリネームしたい場合、以下のようにコマンドを実行します。

```bash
git mv example.txt new_example.txt
```

# 2. git mvの利点
## a. ファイル名の変更とコミットが一括で行える
git mvコマンドを使用すると、ファイル名の変更とそれに伴うコミットが一括で行えます。
これにより、変更履歴が整理され、後で変更を追跡しやすくなります。

## b. ファイルの移動も同時に処理できる
git mvコマンドはファイルの移動にも対応しています。
ファイルが異なるディレクトリに移動する場合も、同じコマンドで一括して処理できます。

# 3. まとめ
ファイル名を変更する際には、git mvコマンドを積極的に活用しましょう。
これにより、クリーンで追跡しやすいコミット履歴を維持できます。また、ファイルの移動にも柔軟に対応できるため、プロジェクトの管理がよりスムーズになります。

以上が、git mvコマンドの基本的な使用法とその利点についての説明でした。
是非、これを参考にして効果的にファイル名の変更を行ってください。
インプット→アウトプットの過程で絶望した駆け出しエンジニアへ

# はじめに
エンジニア一年目のA.Kと申します。よろしくお願いします。
現在、運用保守の案件を担当していますが、フロントエンドに興味を持ち学習を進めています。

**みなさん（特に駆け出しエンジニアの方）、学んだことをアウトプットできていますか？**

初学者ほど「実際に手を動かして学ぶ」過程に対して抵抗があるのではないでしょうか。
わからないって辛いし、これほど自分の無力感を痛感させられることはない。
私も先輩エンジニアに背中を押されて自分で手を動かし始めた身ですが、まさにその渦中にいます。
色々と感じたことがあるので、 **同じように苦しんでいる方の励み** になればと思い記事を書きました。
(内容は私個人の考えがメインであり、有益な情報提供を約束できるものではありません。。)

# 現状
**Reactでサービスの開発**を目指して基礎から学習中です。
（つい一週間前までJavaScriptとは何ぞや。。？状態でした。）

現在の学習状況は以下です。

**終了したインプット**

Udemyの講座受講（JavaScript＋Reactの基礎を学ぶ＆ToDoリスト作成）

https://www.udemy.com/share/103Fxl3@gYLOCeQqoZf5bGNwMQzjnE4LjTiGo_rWj07-w6tcxp15kKY-uEMc13j3QgaBqKnsVg==/

（JavaScriptの基礎から丁寧に解説してくれます。めちゃくちゃわかりやすいです！）

**現在挑戦中のアウトプット**
学習記録アプリの作成
（学習記録データの一覧表示・学習データの入力フォーム作成等）
先輩エンジニアに随時サポートしてもらいながら、自分で必要な機能を実装しています。

# 思ったこと
**いざ実装したい機能をつくるとなると、全然うまくいかない。。！絶望！**
まずは、ぼんやりと「こんな感じの処理だよな。。」っていうのを書いてみる。
しかし、画面には大量のエラー。修正したらまた別のエラー。何がどうなってるんだ。。！
Udemyの講義内容は理解できたし似たような処理も出てきたのに。
今までやってきたことはなんだったんだ？？
AM6:00から半泣き（朝型人間です。）

**インプットだけでは身につかない**
当たり前じゃねえか。。と言われたらそれまでですが。。
特に「Udemyをやってそれっきり」な初学者の方は多いんじゃないでしょうか？
実際に手を動かして学ぶ講座は数多く存在しますが、それだけでは不十分だと痛感しました。
私は **「学習したことを応用しながら、自分が思い描いた処理を実現できるか」** が重要だと思います。

# ありがたき先輩エンジニアからのお言葉
**真の絶望はネットにも答えがない時**
初学者がわからないことって、**大体世の中のエンジニアさんたちがカバー** してくれています。大体みんな同じようなところでつまずきます。
当たり前かもしれませんが、落ち着いて調べれば大体の問題は解決します。
（最近は生成AIも普及しているので、どんどん使っていきましょう。）

**初学者だからこそ提供できる価値がある**
まさにこの記事を投稿するに至った理由になります。
技術ブログなんかに比べたら、こういった挫折経験の記事数はかなり少ないように思います。
**だからこそ、初学者が抱える悩みや感覚を共有することに意味が生まれます。**

# ささやかなTips
エンジニアとしてまだ実績がないので恐縮ですが。。
実際にやってみて効果があったのはこちらです。

**先輩エンジニアとのコネクションをつくる**

**具体的には、エンジニア交流会や勉強会に足を運び、「○○を勉強してるんですけどォ、ちょっと困っててェ。。」と色んな人に話しましょう。**
意外と皆さん助けてくれます。初学者ならなおさら！！

エンジニア＝冷たい、みたいなイメージがあったんですが、実際は全然違いました。
**こうしたイベントには一緒に勉強する仲間を探していたり、自分の技術や知見で人を助けたい、って方がたくさんいます。**
自ら会場へ足を運んで、頼れる関係を構築していきましょう。
# おわりに
今回はアウトプット段階で絶望したお話でした。少しはお役に立てたらいいな。。
今後もサポートしていただいている方々に感謝しながら、根気強く学習を続けていきます。
この辛さに立ち向かえている自分を評価しつつ、どんどん壁を超えていきましょう。
一緒に頑張りましょうね！
JavaScriptから使いやすいWebAPIを考える 2

JavaScriptから使いやすいWebAPIを考える記事の第二弾
第一弾では[RPC風のAPI](https://qiita.com/economist/items/0e1fabdfcd75d1e3bafa)を紹介しましたが、今回はサーバ側に焦点を当てます

## 基本的な説明

WebAPIといえばデータやHTMLを返すのが普通ですが、今回のWebAPIは**描画命令**を返します

```jsonc:サーバが返すのは描画命令
{"$":"#sample", "append":"<li>〇〇</li>"}
```

サーバは描画命令をJSONで返します。

```js:ブラウザ側では次のように実行される
$("#sample").append("<li>〇〇</li>")
```
描画命令はブラウザ側でJavaScriptに変換されて実行されます。

```js:複数の描画命令
[{描画命令1}, {描画命令2}]
```
描画命令は複数同時に送れます。配列に入れるだけです

以上が基本的な説明です。

全体的な流れは次の通りになります。

1. ユーザがリンクを踏んだりフォーム投稿を行う
2. jsonr属性があれば、当プログラムが代理でサーバに送信
3. サーバは描画命令を返す
4. 当プログラムが描画命令を実行する


まだプロトタイプ状態ですが、感触は良好なので記事にしてみました。
以下は命令のリファレンスです。

## タグ選択
```jsonc:タグ選択
{"$":"#sample"}    //$("#sample")
{"$":"*.sample"}   //複数選択
{"find":".sample"} //$(this).find(".sample")
```
|名前|値
|:-:|-
|$|セレクタに一致するタグを1つ選択する<br>省略時は自分自身(イベントが発生した要素)になる
|find|セレクタに一致する子孫を1つ選択する
|closest|セレクタに一致する一番近い親を選択する

セレクタの頭に``*``を付けると複数選択できる

## タグ追加
```jsonc:タグ追加
{"$":"#sample", "inner":"〇〇"}                //$("#sample").html("〇〇")
{"$":"#sample", "inner":"〇〇", "escape":true} //$("#sample").text("〇〇")
```

|名前|値
|:-:|-
|inner|選択タグの内部を変更する
|append|選択タグの内部の最後に追加する
|prepend|選択タグの内部の最初に追加する
|before|選択タグの前に追加する
|after|選択タグの後に追加する
|replace|選択タグを置換する。空文字なら削除になる<br>
|escape|``true``を指定すると、文字列をエスケープする<br>初期値はエスケープしない

## 属性
```jsonc:属性
{"$":"#sample", "attr":{"href":"〇〇"}} //$("#sample").attr("href","〇〇")
{"$":"#sample", "attr":{"onclick":"console.log(event)"}} //イベントを登録する唯一の方法
```

|名前|値
|:-:|-
|attr|``{名前:値}``で属性を変更できる<br>値がnullなら、その属性は削除される

値はエスケープされるので安全です

## プロパティ
```jsonc:プロパティ
{"$":"#sample", "prop":{"disabled":true} //$("#sample").prop("disabled",true)
```
|名前|値
|:-:|-
|prop|``{名前:値}``でプロパティを変更できる
|document|``{名前:値}``でdocumentのプロパティを変更できる
|window|``{名前:値}``でwindowのプロパティを変更できる

値に関数は指定できません

## その他
|名前|値
|:-:|-
|alert|alertを表示する

## 📝ToDo

- 不足してるもの：classAdd,classRemove,dispatch,click
- ブラウザ側の状態をサーバに送るには？ → リンクを検知してhrefを書き換える
- history
- text/htmlの時は全面的に書き換え
- ShadowDOM (composed, event.composedPath()[0], node.getRootNode())
- eval (new Function('target', `"use strict";${json.function}`).bind(json)(target))
- [プロトタイプ](https://gist.github.com/worldace/683eb1106cc65e643e987c3ec4f8a63c)
gorm gen を使用してデータベースから構造体を作成する

# 背景
最近会社でGolangのプロジェクトに入りAPIを作成しています。その際にDBのデータを受け取る構造体を作成するのが非常に面倒でした。特に、gormタグの作成が面倒でスキーマに応じて変更する必要があります。
これを手作業で作成している時、先輩に`gorm gen`があるから使ってみたらと言われ少し触ってみたのでわかったことを書いていきます。

https://gorm.io/gen/database_to_structs.html

# 特定のテーブルのみを作成する
```go:main.go
users := g.GenerateModel("users")
articles := g.GenerateModel("articles")
g.ApplyBasic(users, articles)
g.Execute()
```

# スキーマと異なるテーブル名,カラム名にする
```go:main.go
users := g.GenerateModelAs("users", "changedUsers",
	gen.FieldRename("name", "changedName"),
)
g.ApplyBasic(users)
g.Execute()
```

# queryを作成せずにmodelのみを作成する
エラーが出るけど構造体にのみ作成されるようになる
```go:main.go
g := gen.NewGenerator(gen.Config{
		Mode:          0, // Create only models
})
```

# modelの作成されるディレクトリを変更する
```go:main.go
g := gen.NewGenerator(gen.Config{
	Mode:          0, // Create only models
    ModelPkgPath:  "./changedDirectory",
})
```

## 最後に
現状色々試していて問題点があり参考程度に流すだけで、これを本格的に導入することは無くなりました。
Gen Toolがあったのでそちらも少し触ってみて良さそうだったらまた記事に書いてみます。

### 不満点
- スキーマがint32の時、swaggerで作成された型不一致するため、int32をintに揃える必要がある。`gen.FieldType`を使用すれば変換できるが全てに書くのが面倒。
- スキーマにコメントが入っている時`// ユーザー名`コメントアウトが追加される。`gen.FieldComment`を使用すれば変換できるが全てに書くのが面倒。
- リレーションもジェネレートしてくれると思いきや、書く必要がある。
laravelのCollectionについて簡単に紹介〜〜

## はじめに
みなさんはある配列の特定の条件を満たしている値がだけ取得したい時はどうしますか？
半年前の自分であれば
・ループしてif文で条件決めて、、、
・array_filterで特定条件の値だけ、、、
などのことを行なっていたと思いますが、現在はCollectionを使うことが多くなりました。
なので備忘録ということも混みでCollectionについて書こうと思います。

## Collectionとは？？
Collectionとは簡単に言うと配列を簡単に操作するための便利なラッパーです。
使用することでフィルタリングやソートといった工程も簡潔に行うことが可能になります。

## Collectionの使用方法
### まず行うこと（準備）
namespace（名前空間）を書く。
```
use Illuminate\Support\Collection;
```
collectionに使用する配列を用意し、collectionを使用
```  
// サンプルの配列
$array = [1, 2, 3, 4, 5];

// Collectionの生成
$collection = collect($array);
```
これだけデータを操作する準備が整いました！
Collectionで使用できるメソッドは多いので自分が開発でよく使用するメソッドを3つ紹介します。
### filter
filterメソッドは文字通りデータをフィルタリングするときによく利用します。
フィルタリングする条件は数値の比較、文字列の一致も可能です。
```
// サンプルの配列
$array = [1, 2, 3, 4, 5];

$collection = collect($array);
$filter = $collection->filter(function (int $value, int $key) {
    return $value > 3;
})->all();

// 実行結果：[4, 5];
```

### pluck
plickメソッドは配列のキーに対応している値を返します。
```
$users = [
    ['id' => 1, 'name' => 'Harry'],
    ['id' => 2, 'name' => 'Ron'],
    ['id' => 3, 'name' => 'Jordge'],
];

$collection = collect($users);
// 'name' キーに基づいて値を抽出
$names = $collection->pluck('name')->all();

実行結果：['John', 'Jane', 'Jordge']
```
### map
mapメソッドはcollectionに変換したデータを繰り返しで返します。またmapメソッド内で新しい値に変更することもできます。

```
// サンプルのデータ
$data = [1, 2, 3, 4, 5];
$collection = collect($data);

// mapメソッドを使用して各要素を2倍にする
$doubledValues = $collection->map(function ($value) {
    return $value * 2;
})->all();

//実行結果 : [2, 4, 6, 8, 10]
```
## 最後に
今回は簡単ではありますが、Collectionについて紹介しました。
他にもCollectionで出来ることは多いのでぜひ試してみてください！！
パルワールド鯖の設定値一覧[2024/1/24時点]palworld

# 設定ファイルの場所
:::note info
設定ファイルを修正する前に鯖を停止し、修正後再起動してください
:::


### Windows
```
c:/インストールした場所/steamapps/common/PalServer/Pal/Saved/Config/WindowsServer/PalWorldSettings.ini
```
### Linux
```
/インストールした場所/steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini
```

# 設定一覧
:::note info
パルワールドの鯖を立てた際に設定できる項目を纏めました。
2024/1/24時点の項目ですので今後変わる可能性があります
:::
|設定名|デフォルト値|設定説明|
|:-:|:-:|:-:|
|Difficulty|None |none=ノーマル hard=ハード|
|DayTimeSpeedRate|1|お昼のスビード倍率|
|NightTimeSpeedRate|1|夜のスビード倍率|
|ExpRate|1|経験値倍率|
|PalCaptureRate|1|パル捕獲倍率|
|PalSpawnNumRate|1|パル出現数倍率|
|PalDamageRateAttack|1|パル与ダメージ倍率|
|PalDamageRateDefense|1|パル被ダメ倍率|
|PlayerDamageRateAttack|1|プレイヤー与ダメージ倍率|
|PlayerDamageRateDefense|1|プレイヤー被ダメ倍率|
|PlayerStomachDecreaceRate|1|プレイヤー食料倍率|
|PlayerStaminaDecreaceRate|1|プレイヤースタミナ倍率|
|PlayerAutoHPRegeneRate|1|プレイヤー自動HP回復倍率|
|PlayerAutoHpRegeneRateInSleep|1|プレイヤー睡眠中自動HP回復倍率|
|PalStomachDecreaceRate|1|パル食料倍率|
|PalStaminaDecreaceRate|1|パルスタミナ倍率|
|PalAutoHPRegeneRate|1|パル自動HP回復倍率|
|PalAutoHpRegeneRateInSleep|1|パルHP回復倍率|
|BuildObjectDamageRate|1|建築オブジェクトダメージ倍率|
|BuildObjectDeteriorationDamageRate|1|建築オブジェクト風化ダメージ倍率|
|CollectionDropRate|1|収集ドロップ倍率|
|CollectionObjectHpRate|1|収集オブジェクトHP倍率|
|CollectionObjectRespawnSpeedRate|1|収集オブジェクドロップスピード倍率|
|EnemyDropItemRate|1|敵ドロップアイテム倍率|
|DeathPenalty|All||
|bEnablePlayerToPlayerDamage|False|プレイヤー間のダメージを有効にする|
|bEnableFriendlyFire|False|フレンドリーファイアを有効にする|
|bEnableInvaderEnemy|True|侵略者敵を有効にする|
|bActiveUNKO|False|アクティブUNKO|
|bEnableAimAssistPad|True|エイムアシストパッドを有効にする|
|bEnableAimAssistKeyboard|False|エイムアシストキーボードを有効にする|
|DropItemMaxNum|3000|ドロップアイテム最大個数|
|DropItemMaxNum_UNKO|100|UNKOドロップアイテム最大個数|
|BaseCampMaxNum|128|ベース拠点の最大数|
|BaseCampWorkerMaxNum|15|ベース拠点のワーカー最大数|
|DropItemAliveMaxHours|1|ドロップアイテムの生存最大時間|
|bAutoResetGuildNoOnlinePlayers|False|自動リセットギルドオンラインプレイヤーなし|
|AutoResetGuildTimeNoOnlinePlayers|72|自動リセットギルド時間オンラインプレイヤーなし|
|GuildPlayerMaxNum|20|ギルドプレイヤー最大数|
|PalEggDefaultHatchingTime|72|パル卵初期値孵化時間|
|WorkSpeedRate|1|作業スピード倍率|
|bIsMultiplay|False|bIs マルチプレイ|
|bIsPvP|False|bIs PvP|
|bCanPickupOtherGuildDeathPenaltyDrop|False|他のギルドのデスペナルティドロップを拾うことができます|
|bEnableNonLoginPenalty|True|非ログインペナルティを有効にする|
|bEnableFastTravel|True|ファストトラベルを有効にする|
|bIsStartLocationSelectByMap|True|開始場所をマップで選択|
|bExistPlayerAfterLogout|False|ログアウト後の存在プレーヤー|
|bEnableDefenseOtherGuildPlayer|False|防御を有効にするその他のギルドプレイヤー|
|CoopPlayerMaxNum|4|協力プレイヤー最大数|
|ServerPlayerMaxNum|32|サーバープレーヤー最大数|
|ServerName|Default Palworld Server|サーバー名|
|ServerDescription||サーバー説明|
|AdminPassword||鯖管パスワード|
|ServerPassword||鯖パスワード|
|PublicPort|8211|ポート|
|PublicIP||グローバルIP|
|RCONEnabled|False|RCON有効|
|RCONPort|25575|RCONポート|
|Region||地域|
|bUseAuth|True|認証使用|
|BanListURL|https://api.palworldgame.com/api/banlist.txt|BAN一覧url|
Nginx: *.pfx を変換して、証明書を使う

参考ページ
[PKCS#12（pfx）形式から、秘密鍵、公開鍵形式への変換方法](https://knowledge.digicert.com/ja/jp/solution/SO2876)

## 前提
example2024.pfx と　パスワードが与えられているとします。

## キーペアファイルに変換

```bash
openssl pkcs12 -in ./example2024.pfx > keypair.txt
```

keypair.txt をエディターで2つのファイルに分割

```text
example2024.key.org
example2024.crt
```

確認

```bash
openssl rsa -noout -text -in example2024.key.org
```

```bash
openssl x509 -noout -dates -in example2024.crt
```

## example2024.key.org をパスフレーズなしに変換

```bash
openssl rsa -in example2024.key.org -out example2024.key
```

example2024.key の確認

```bash
openssl rsa -noout -text -in example2024.key
```

## サーバーの設定

example2024.key, example2024.crt を、/etc/nginx/certificates に置く

/etc/nginx にシンボリックリンクを作成

```bash
cd /etc/nginx
sudo ln -s certificates/example2024.key example.key
sudo ln -s certificates/example2024.crt example.crt
```

Nginx の設定が正しいか確認

```bash
sudo nginx -t
```

Nginx を再起動

```bash
sudo systemctl restart nginx
```

ブラウザーでアクセスして、有効期限を確認

## 使用したバージョン

```text
$ openssl --version
OpenSSL 3.3.1 4 Jun 2024 (Library: OpenSSL 3.3.1 4 Jun 2024)
```
iPhoneの通知設定画面のラジオボタンを再現してみた

# 概要

SwiftUIでラジオボタンで設定を切り替える機能を作成することがあったので、どうせなら公式アプリの設定画面に見た目を似せてみようと思い、作成しました。

再現したい画面はこちらです。

![Image (5).jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/318ef5af-aaee-b978-89ac-1ef047b13b1d.jpeg)

再現した画面はこちらです。

![Simulator Screen Recording - iPhone SE (3rd generation) - 2024-01-24 at 18.14.25.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/96be3c99-0b67-ecd8-e3e3-f8bddc3ca000.gif)


# 詳細

今回作成した選択項目は`QR`と`NFC`となっています。
また、こちらで選択した値はアプリで共有して使用すること、そしてアプリ内で保持することを前提としているため、`@AppStorage("QR") var scanType = "QR"`
と記述しています。

UIに関することなので、残りは以下のSwiftUIのコードを参照していただければ幸いです。

```Swift
import SwiftUI

/// 設定画面
struct SettingView: View {
    @AppStorage("QR") var scanType = "QR"
    
    var body: some View {
            List {
                Section(header: Text("読み取り形式"),
                        footer: Text("読み取り方法を決定する項目です。")) {
                    VStack {
                        HStack {
                            Spacer()
                            ScanTypeView(scanType: $scanType, type: "QR", imageName: "qr_viewfinder")
                            Spacer()
                            ScanTypeView(scanType: $scanType, type: "NFC", imageName: "nfc")
                            Spacer()
                        }
                        .padding()
                    }
                }
            }
            .navigationTitle("設定")
            .navigationBarTitleDisplayMode(.inline)
        }
    }

    struct ScanTypeView: View {
        @Binding var scanType: String
        let type: String
        let imageName: String
        
        var body: some View {
            VStack {
                Image(imageName)
                    .resizable()
                    .frame(width: 48, height: 96)
                    .foregroundColor(scanType == type ? .blue : .gray)
                Text(type)
                    .padding(scanType == type ? 10 : 0)
                    .background(scanType == type ? Color.blue : Color.clear)
                    .cornerRadius(25)
                    .frame(width: 82, height: 36)
                    .foregroundColor(scanType == type ? .white : .gray)
            }
            .onTapGesture {
                withAnimation(.easeInOut(duration: 2.0)) {
                    scanType = type
                }
            }
        }
    }



public enum scanType {
    /// QRコードでスキャンを行う場合
    case QR

    /// NFCでスキャンを行う場合
    case NFC

}
```

ただのテキストのみのラジオボタンだけではなく、画像付きだとより分かりやすいですね。
【25卒大学生】エンジニア就活で意識していたこと

# はじめに
私は学部3年でエンジニア就活（web系）をしていた25卒です。
就活の時に実践していたこと・意識していたことなどを書こうと思います。

# 就活開始前の技術レベル
* 情報系よりの文理融合の学部
* 授業ではpython、JavaScript、C(少しだけ)

# 就活の時系列
### 2年生
1月　ITパスポートの勉強を始める
3月　学校の就活セミナーに参加(就活開始)

### 3年生
4月　ITパスポート合格・基本情報の勉強を始める
5月　個人でwebアプリを作る・アウトプットを意識し始める(GitHubとQiita)
6月　インターン申込
7月　インターン申込
8月　インターン参加(3社)・基本情報合格・応用情報の勉強を始める
9月　インターン参加(1社)
10月　ハッカソン初参加・応用情報の試験を受ける(12月に合格通知)
11月　早期選考(本選考)の申込
12月　ハッカソン参加(2つ)・本選考面接(2社)・内定
→ 就活終了


# 意識したこと・実践したこと
1. 早く始めれば早く終わる
1. とりあえず資格は取る
1. 授業以外でも開発する
1. アウトプットを意識
1. ハッカソンに参加する
1. 夏インターンに参加する
    * 3日以上のインターン
    * 参加するまでに選考があるインターン
    * 現場受け入れ型インターン
1. インターン先で友達を作る
1. 第一志望の企業を見つける


## 1. 早く始めれば早く終わる
私は2年生の3月に就活をスタートしました。

インターンで会う人の中には2年生から長期インターンに参加している人や、夏休みで内定を持っている人もいました。

就活は早く始めれば、それだけ早く終わります。特に、エンジニア職は文系職よりも早く決まりやすいと思います。

人事担当の方によれば、エンジニア職はスキルが定量化しやすいから選考を早く進めやすいそうです。一方、文系職はスキルの定量化が難しく、ポテンシャルを見るために選考が長くなりやすいそうです。

## 2. とりあえず資格は取る
高い技術力を持っている人は必要ないかもしれませんが、普通の学部生にとって、資格は無いよりあった方が断然いいです。

履歴書の免許・資格欄に何かしら書ける資格を持っておくと、安心できました。
また、面接でコンピュータサイエンスについて聞かれることがあったので、基本知識は持っておいた方が良いと思いました。

私的おすすめ資格は基本情報、応用情報、TOEIC、LPIC(エルピック)です。


## 3. 授業以外でも開発する
私は、自分が行きたい職種に関連したものを開発する経験を積むことを意識していました。

開発と聞くと難しく感じますが、フレームワークを1つ学ぶだけである程度は作れるようになります。
web系はVue.jsかReactが情報豊富でおすすめです。

私が初めて開発したのは、3年生の5月ごろで、ECサイトのモックのようなものを作りました。
コードは綺麗ではなかったですが、「webアプリを作る」ことを目標にしていました。


## 4. アウトプットを意識する
技術職のES(エントリーシート)にはGitHubのリンクやポートフォリオを書くところがありました。そこにリンクを書いておくことで、面接時に話すことができるので自己PRになりました。

私は主にGitHubとQiitaでアウトプットしていました。
作ったアプリをデプロイできるのが理想でしたが、そこまでの技術力はなかったので、ローカルで作ったものをGitHubに上げていました。

Qiitaでは、開発時に困ったことや解決策、授業で習ったことなどを書くことが多かったです。

## 5. ハッカソンに参加する
ハッカソンに参加することで、技術力が上がる＆ガクチカを作ることができました。

私は就活を始めてから、3回ハッカソンに参加しました。
最初のハッカソンは「技育キャンプ」が主催しているハッカソンでした。初心者も参加しやすいのでおすすめです。

## 6. 夏インターンに参加する
私は夏のインターンに4社参加しました。オフライン3社、オンライン1社です。

正直、オンラインはあまり有益ではありませんでした。会社のことを知るという目的ならいいと思いますが、私がオンラインのインターンに参加した時は得られるものが少ないと感じました。

オフラインは会社の雰囲気が知れる、他のインターン生と情報交換できる所が良かったです。

特に、**「インターン期間が3日以上、選考がある、現場受け入れ型」** がおすすめです。

### インターン期間が3日以上
インターン期間が長い方が、他のインターン生と話す機会が増えます。

インターン生の中には内定が決まっていたり、技術力の高い人がいるので、自分が成長するチャンスになりました。
また、就活市場の中での自分の位置を知る事ができました。

### インターンに参加するまでに選考がある
インターンの段階で選考があると、本選考の回数が少なかったり、早期選考をしている企業が多いのでおすすめです。

### 現場受け入れ型
現場受け入れ型とは、実際に社員の方々が働かれている現場で実施されているインターンのことです。
見分け方としては、インターンの内容に「自社のプロダクトに携わるインターン」などの記載があるものです。

現場受け入れ型のインターンに参加することで、社員の方と話せる機会が増えたり、実際に自分が働く事を想像できました。

## 7. インターン先で友達を作る
エンジニア職のインターンに参加している学生は院生がほとんどで、優秀な人が多かったです。
友達になることで色々教えてもらえたり、インターン終了後も就活の話や技術の話を聞けてモチベーションアップにも繋がりました。

## 8. 第一志望の企業を見つける
面接を受けてみて、なんとなく本選考を受けても受からないと思いました。
面接時に志望理由は必ず聞かれるので、第一志望の企業を見つけて、志望理由を明確にすることが大切だと思いました。

# 就活で後悔したこと
* 長期インターンに参加する
* 社員の方にもっと質問する
## 長期インターンの参加する
ハッカソンで長期インターンに参加している人の話を聞いて、私も参加すればよかったと思いました。
長期インターンに参加することで、仕事でのコードの書き方・プルリクの書き方を知る事が出来ると思いました。

## 社員の方にもっと質問する
社員の方になんでも聞けるのはインターンだけです。
仕事の事や面接対策など、もっと聞いておけばよかったと思いました。

# まとめ
今回は私が就活をする中で意識したこと・実践したこと・後悔したことなどについて書きました。
エンジニア就活を考えている人の手助けになれば幸いです。