OmniAICreator/Qiita-1.07M huggingface dataset:
ChatGPTがpythonで書いた「じゃんけん」のコード

Pythonでじゃんけんのプログラムを書く方法はいくつかありますが、以下にシンプルな例を示します。

```python:janken.py
import random

def janken(player_choice):
    options = ["グー", "チョキ", "パー"]
    computer_choice = random.choice(options)
    
    print(f"あなたの選択: {player_choice}")
    print(f"コンピュータの選択: {computer_choice}")

    if player_choice == computer_choice:
        print("引き分けです。")
    elif (player_choice == "グー" and computer_choice == "チョキ") or \
         (player_choice == "チョキ" and computer_choice == "パー") or \
         (player_choice == "パー" and computer_choice == "グー"):
        print("あなたの勝ちです！")
    else:
        print("コンピュータの勝ちです。")

player_choice = input("じゃんけん: グー、チョキ、パー のいずれかを入力してください: ")
janken(player_choice)
```
このプログラムでは、janken() 関数を定義しています。この関数は、プレイヤーの選択（"グー"、"チョキ"、"パー"）を引数として受け取り、コンピュータの選択をランダムに決定します。その後、両者の選択を表示し、結果を判定して勝敗を表示します。

プログラムの最後に、input() 関数を使ってプレイヤーに選択を入力させ、janken() 関数を呼び出してじゃんけんを実行しています。
React で file upload する方法

`input tag` に `Change Event Handler` を指定する。

```tsx
export default function UploadFile() {
  
  const [formState, setFormState] = useState<File>();

  const onFileInputChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const { files } = event.currentTarget;
    
    if (files === null)
      return;

    const file = files[0];
    setFormState(file);
  }
  return (
    <input
      type="file"
      onChange={onFileInputChange}
    />);
}
```

form で選択した file が `FileList` 型で files プロパティの中に入っている。
`input type` が `file` 以外の時、`event.currentTarget.files` は `null` になる。
文字列の置換を行う方法

文字列の置換を行う場合には、
文字列`str`の`replace()`メソッドを利用する。


まずは基本的な使い方から説明します。
`replace('【置換前文字列】', '【置換後文字列】')`で、
「置換前文字列」を「置換後文字列」に置き換えることができます。

具体的なソースを元に説明します。
```Python
# 文字列の定義
example_str = "aaa bbb ccc"

# 文字列を置換して表示
print(example_str.replace('aaa', 'ddd'))

# 元の文字列を表示
print(example_str)
```
これを実行すると、
1つ目の`print`行では「example_str」内の「aaa」という文字列が「ddd」に置換され、
`ddd bbb ccc`と表示されます。

なお、元の文字列自体が置換されて変更されるわけではないので、
2つ目の`print`行では`aaa bbb ccc`と表示されます。

　
続いて置換回数を指定する使い方について説明します。
`replace('【置換前文字列】', '【置換後文字列】', '【最大置換回数】')`で、
「置換前文字列」を「置換後文字列」に、【最大置換回数】だけ置き換えることができます。

具体的なソースを元に説明します。
```Python
# 文字列の定義
example_str = "aaa bbb ccc"

# 文字列を置換して表示
print(example_str.replace('a', 'd', 2))
```
これを実行すると、
`print`行では「example_str」内の「a」という文字が「d」に置換されていきますが、
最大置換回数が「2」と指定されているため
`dda bbb ccc`と表示されます。


さらに複数文字を置換する使い方について説明します。
`replace()`メソッドにはそのような機能は無いため、
`replace()`メソッドを繰り返し適用することで実現する。

具体的なソースを元に説明します。
```Python
# 文字列の定義
example_str = "aaa bbb ccc"

# 文字列を置換して表示
print(example_str.replace('a', 'd').replace('b', 'e').replace('c', 'f'))
```
これを実行すると、
`print`行では「example_str」内の
「a」という文字が「d」に、
「b」という文字が「e」に、
「c」という文字が「f」に
それぞれ置換されて、
`ddd eee fff`と表示されます。

:::note info
文字列の置換には、正規表現も使える`sub()`関数も用意されています。
https://docs.python.org/ja/3/library/re.html#re.sub
:::
【Javascript】fetchを使って非同期サーバー処理を行い成否を検知して処理を分岐する( Response.ok プロパティ)

## したいこと
Viewに配置されているボタンをクリックしたら、非同期でサーバー処理を行いその処理の成否でjavascript上で処理を分岐する。

## 背景
開発運用中のシステムに機能追加を行う場面でのお話

## 実装していくよ〜
### まずは既存コードから探してみる
既存のコードの中にfetchを使用して今回したいことと同じことをしている箇所を発見したので、そのまま倣ってみる。
```
Button.onclick = () => {
        const url = 'xxxx.com'
        fetch(url, {
            method: 'POST',
            headers: {〜〜〜〜}
        })
        .then(() => {
            console.log('通信成功');
            // 成功時の処理
        })
        .catch(() => {
            console.log('通信失敗');
            // 失敗時の処理
        });
    }
```
このコードを読んで、サーバー側で例外が発生したときに、サーバーエラーレスポンス（500~599）で返すので、その際は catch に入って失敗時の処理ができると予想した。

## ステータス500で返しても catch 入らなくね？
となった。
fetch を使うのはほぼ初めてで予想と違う結果に戸惑った。レスポンスの返し方が悪いのか、返している値が悪いのかと、30分くらいガチャガチャ実験していた。

こういうときは基本に立ち返るべし！

と、公式リファレンスを読んでみると、冒頭でいきなり
> fetch() のプロミスはネットワークエラーが発生した場合（普通は権限の問題があったときなど）のみ拒否されます。 fetch() のプロミスは HTTP エラー（404 など）では拒否されません。代わりに、 then() ハンドラーで Response.ok や Response.status プロパティをチェックする必要があります。

まさにこれやん！

HTTPエラーでは拒否されないと書いてあるので、いくらステータスエラーを返してもcatchに入ってくれないようだ。だが、そもそもやりたかったのは分岐処理だ。レスポンスからサーバー側のエラーを検知できれば問題なし。それもココで書いてある Response.ok でその検知ができそうだ。
```
Button.onclick = () => {
        const url = 'xxxx.com'
        fetch(url, {
            method: 'POST',
            headers: {〜〜〜〜}
        })
        .then((response) => {
            console.log('通信成功');
            
            if(response.ok) {
                // 成功時の処理
                console.log('処理成功');
            } else {
                // 失敗時の処理
                console.log('処理失敗');
            }
        })
        .catch(() => {
            console.log('通信失敗');
        });
    }
```
なるほど！これでサーバー側の例外を検知することができるようになった！

## おわりに


既存コードにあったとしても、知らないことについては、まず公式ドキュメントなどを読もう。


## 参考
https://developer.mozilla.org/ja/docs/Web/API/fetch
IntelliJ IDEA で爆速開発するために刻むべき10のショートカット

# ショートカットつかってますかーー！！
開発の高速化といえばマウスレスコーディングは基本だと思います。
私は普段 IntelliJ IDEA を主に使っているので、高速化するためにおすすめのショートカットを紹介します。

## Cmd + Shift + F ： 全体検索
よく使う検索「Cmd + F」の全体バージョンです。同様のコードを探すとき、参照箇所、参照元を探す際など万能に使えます。検索の際に指定できるオプションもいくつか覚えておくとより高速化に繋がります。
## Shift + Shift : なんでも検索
ファイル、シンボル、アクション、ショートカットなど様々な名称を検索することができます！ 困ったときはとりあえずシフトシフト！！
## Cmd + 1 : プロジェクトツリーを表示
慣れてくると「Shift + Shift」でファイル移動は高速化できるのですが、ツリーで移動したい派の人はこちらのショートカットを覚えておくとよいです。繰り返す押すことで閉じたり、開いたり繰り返すことができます。
## Shift + F6 : リファクタ名前変更
変数名、クラス名などの名称をあとから変更する際は基本的にこの機能で行います。参照、コメントの中までも検索して変更してくれるのでとても便利です。
## Cmd + Shift + R : 全体置換
リファクタでうまく名称変更できない場合などに使用します。フロントのcssクラス名などもまとめて変更したい際に便利です。
## Cmd + Shift + - : コード全体を折りたたむ
行数の多いコードから目的のメソッドだけを表示したいときなど、とりあえずコード全体を折りたたみます。
## Cmd + E : ウインドウ履歴
開いたファイル履歴が表示されます。直前に開いていたファイルがフォーカスされた状態で1番上に表示されるので「Cmd + E」→「Enter」と叩くことで直前のファイル間を行き来することができます。
## Control + R ： 再実行
テストなどなんども実行することが多い場合に便利な機能です、直前の実行をもう一度行います。
## Opt + Shift + U ： スネークケースとキャメルケースの切り替え
クラス名 → 変数名などの変換の際に覚えておけば便利なショートカットです。
## Shift + Esc ： 下部ツールバーをたたむ
コード編集の際、一度に見える行数が少ないのは許せないので、なるべく表示領域を広げるためにすぐたたみます！

# さいごに
ショートカットを極めてマウスレスで高速なコーディングライフを！！
【AI】入門記事リンク集【ChatGPT / GitHub Copilot / Notion AI】

# 0. はじめに
## 0-1. 全体の流れ
> [1.ChatGPT](#1-chatgpt)
> [2.Copilot](#2-copilot)
> [3.NotionAI](#3-notionai)

## 0-1. TL;DR
- ChatGPT / GitHub Copilot / Notion AIの教材や参考リンク集まとめ

# 1. ChatGPT

https://zenn.dev/stafes_blog/articles/76e84b39f3de94

https://zenn.dev/umi_mori/articles/what-is-gpt-4

https://zenn.dev/waarrk/articles/a6868cea7549de

https://zenn.dev/nameless_sn/articles/chatgpt_cheat_sheet

https://zenn.dev/nameless_sn/articles/the_pros_and_cons_about_chatgpt

https://zenn.dev/kazuwombat/articles/5617468b97fa3f

https://zenn.dev/fumi_sagawa/articles/932bcaafd28c53

https://zenn.dev/vim_jp/articles/26eb77fea1e9a4

https://zenn.dev/bolmatu/articles/4cacb9072750fe

https://qiita.com/tak001/items/7605f0be7b424118e5a5

https://qiita.com/tak001/items/748f648900dc88419434

https://qiita.com/ryome/items/0408153a685848cc33dc

https://qiita.com/tak001/items/6a39da97e2f3e5d4eb08

https://qiita.com/sakasegawa/items/82069c97a1ee011c2d1e

https://qiita.com/devneko/items/0dc9fd8b37419d9e369c

https://chrome.google.com/webstore/detail/superpower-chatgpt/amhmeenmapldpjdedekalnfifgnpfnkc

https://chrome.google.com/webstore/detail/webchatgpt-chatgpt-with-i/lpfemeioodjbpieminkklglpmhlngfcn

https://chrome.google.com/webstore/detail/sharegpt-share-your-chatg/daiacboceoaocpibfodeljbdfacokfjb

# 2. Copilot

https://zenn.dev/gon/articles/06fe05730f8294

https://zenn.dev/riya_amemiya/articles/7a7cec9244e4b9

https://zenn.dev/ichii731/articles/8ec3114381c6f6

https://qiita.com/tak001/items/c6bca65d67843c24478f

https://qiita.com/flutter_daisuki/items/6d6e663a089c1a26fa56

https://qiita.com/tak001/items/9ef12a924469b0370c01

# 3. NotionAI

https://zenn.dev/umi_mori/articles/notion-ai-writing-blog-for-engineer-tips

https://zenn.dev/takiko/articles/fb73f70581e08f

https://zenn.dev/nokonpt/articles/notionai-rewrite

https://qiita.com/namizatork/items/b23edefc4165ecc8fda1

https://qiita.com/good_engineer00/items/736c7ef8d2d64bdecf86
【zsh】コマンドの先頭に"="をつけてコマンドのフルパスに置き換える

# 備忘録

あるコマンドのフルパスを取得したいとなった時、
一般的に"which"コマンドを用いて取得するといった方法がメジャーである。

zshにおいては、コマンドの先頭に"="を入れることで、
そのコマンドをフルパスに置き換えることが可能。

## 例
```zsh
#1 echoで表示してみる
% echo =ls
/bin/ls

#2　変数に格納してみる
% var==ls
% echo $var
/bin/ls

#3 そのまま実行してみる
%  =echo "hello"
hello

```
### #1 echoで表示してみる
lsコマンドの先頭に"="を書き、それをechoすることで
"=ls"がコマンドの実態"/bin/ls"に置き換わっていることを確認できる。

### #2 変数に格納してみる
フルパスに置き換わった文字列を変数に格納している。
"="が２連続するという特殊な書き方だが、
エラーにならず、ちゃんと変数に格納される。

### #3 そのまま実行
=をつけようがつけまいが、表示される結果は変わらないが、
"/bin/echo"のフルパス実行しているものと認識。

## whichと比較
自分の環境ではlsは"ls -G"のエイリアスとなっている。
この状態でwhichコマンドを使用すると以下のような結果が返ってくる。
```zsh
% which ls
ls: aliased to ls -G
```
一方"=ls"の場合は
先述の例のように、aliasの設定関係なしに、
lsの実態を示すことができた。

## もう少し詳細

### マニュアル

>`=' expansion
>If a word begins with an unquoted `=' and the EQUALS option is set, the remainder of the word is taken >as the name of a
>command. If a command exists by that name, the word is replaced by the full pathname of the command.

「zshのシェルオプションに"EQUALS"がセットされている環境では、コマンドの先頭に"="を書くとフルパスに置き換える」的なことが書いてあると思われる。

### シェルオプションを調べる

```zsh
% setopt
combiningchars
interactive
login
monitor
shinstdin
zle
```
"EQUALS"の記載は見当たらない...

```zsh
% unsetopt | grep noeq
noequals
```
なるほど、
"noequals"が無効化されている→equalsが有効ということだろう。

### シェルオプション”EQUALS”はデフォルトで設定されているか
```zsh
% man zshoptions
```

> EQUALS \<Z\>
>              Perform = filename expansion.  (See the section `Filename
>              Expansion'.)


同マニュアルの以下説明から\<Z\>はzshにおいてデフォルトオプションであることが伺える。

>DESCRIPTION OF OPTIONS

>DESCRIPTION OF OPTIONS
>       In the following list, options set by default in all emulations are
>       marked \<D\>; those set by default only in csh, ksh, sh, or zsh
>       emulations are marked \<C\>, \<K\>, \<S\>, \<Z\> as appropriate.  When listing
>       options (by \`setopt\', \`unsetopt\', \`set -o\' or \`set +o\'), those turned
>       on by default appear in the list prefixed with \`no\'.  Hence (unless
>       KSH_OPTION_PRINT is set), `setopt' shows all options whose settings are
>       changed from the default.

つまり、デフォルトで有効であると考えられる。

## 環境
OS:macOS Ventura 13.3
zsh:zsh 5.9 (x86_64-apple-darwin22.0)
install CUDA for Debian11

# official document
https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#debian


# clean
既存の package があれば clean する
**xorg の設定なども消える可能性が高いので, ご注意**

```
sudo apt-get --purge remove nvidia-*
sudo apt-get --purge remove cuda-*
```

# install
```
sudo add-apt-repository contrib
sudo apt-key del 7fa2af80

wget https://developer.download.nvidia.com/compute/cuda/repos/debian11/x86_64/cuda-keyring_1.0-1_all.deb
sudo dpkg -i cuda-keyring_1.0-1_all.deb
```

```
sudo apt-get update
sudo apt-get --allow-releaseinfo-change update
sudo apt-get -y install cuda

sudo reboot
```

以下で device 情報が参照できれば完了
```
nvidia-smi
```
ChatRWKV を試行する

# 目的
- ChatRWKV を CPU で動作させる
- あわよくば GPU で動作させる





# 環境
- debian11
- cpu ryzen 1700
- geforce 1080 8G
- mem 64G
- m.2 1T
- swap 500G
- python 3.9



## GPU での動作状態
動作速度が十分なのは見てとれると思います

![rwkv.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118627/ceb20095-0f73-e729-c034-14ab93f5ea06.gif)




# RWKV について
## rwkv-lm
rwkv-lm は, RNN の LLM

https://github.com/BlinkDL/RWKV-LM



## ChatRWKV
https://github.com/BlinkDL/ChatRWKV






# setup

## download model
実行に用いる model を download する.
様々あるので, 後述の source に記述されている model を落とすと良いと思う.
// model size(3b, 7b, 14b など)によって必要環境が異なるので, mem 容量などと相談

https://huggingface.co/BlinkDL



## install 
``` sh
git clone https://github.com/BlinkDL/ChatRWKV.git
cd ./ChatRWKV

pip install -r requirements.txt
pip install torch
```



## processer 選択
``` sh
cd v2
vi chat.py
```

``` python
# 以下のコメントを外し
args.strategy = 'cpu fp32'

# 以下をコメントする
args.strategy = 'cuda fp16'
```

- GPU を使用する場合は, 上記の逆の設定にする
- fp16i8 を選択すると memory 消費量が低減される



## model 選択
先程落とした model file を選択する
``` python
args.MODEL_NAME = 'DLした model を記述'
```




## 実行

``` bash
python chat.py
```





# 所管
- CPUでは動作がだいぶ遅い.
    - 1文字数秒かかる
    - まともに会話できる速度ではない
    - マルチスレッドで動いていない様に見える
- GPU
    - 実用的な速度で反応してくれる
    - 大きな model を実行するには大量のGPU memory が必要
        - 8G では, 7B model を使用できず
- 計算量
    - 大量の計算資源が必要なのがわかる
- mac: m1, mem 16G
    - 大容量 model は mem 不足かまともに動かない
職場でExcel等使うときのポイントメモ

＊基本的にはあくまで個人的なメモです。

・セルの結合は原則使わない方向で
　デザイン上どうしてもな場合はまぁいいが...あと、内容の再利用がない、wordの代わりでデザインする一時的なファイルなら特に問題はないが。

・ショートカットキーは便利。ではあるがすべてを覚えようとすると大変だし、頻度の少ないものなら大した時短にもならない。

・別のシートの参照は極力避ける(やるとしたらくし刺し)。ましてや別のブックの参照は特別な理由がない限りやらない。

・列や行の非表示は、非表示機能を使うのも間違いではないが、アウトライン機能を使ってたたむ方がいい

・シート名は内容がわかる名前で、かつ可能なら短くする。ある程度の長さが欲しいのはやまやまだが、長くすると目的のシートを見つけにくくなるから。

・逆にファイル名については必要な部分を付けたうえで説明的な文を加えてもいい気はする。まぁ賛否両論でしょうけど

・カスタムな表示形式は注意が必要。必要な部分だけうまく使うなら便利だが、他の人が理解せずに使うとちょとだけ面倒なことになりえるので気を付けて使うこと。

・
[CentOS 6.x]SSL接続エラー（Curl update）

お疲れ様です。　キムです。
今回はSSL接続に関して投稿いたします。



---
### エラーの概要
CentOS 6.xバージョンでSaaSへのデータ移行作業の中、SSL接続にエラーが発生しました。
何が原因なのかデータ移行ツールの製造元の方にお問い合わせした結果、Centos6.ｘはサポート対象外のOSとなり、詳しい対応は出来ませんとの事でした。
CentOSは基本RHEL６のOSなので、RHEL６の資料を参照すれば何とかなれるはず。。

---
### 原因
CentOS6.x環境が古かった為、curlを使用してSSLサイトに接続をする時古い規格原因
・古い規格の TLS1.2 での接続方式
・SSLv3

---
### 解決策
古めのCurlをアップデートすれば　OK

1. 下記のコマンドでCentOS-Base.repoファイルの中身を編集する
```
$ sudo sed -i -e "s/^mirrorlist=http:\/\/mirrorlist.centos.org/#mirrorlist=http:\/\/mirrorlist.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo
$ sudo sed -i -e "s/^#baseurl=http:\/\/mirror.centos.org/baseurl=http:\/\/vault.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo
```

２. curlとnssの更新
```
$ sudo yum -y update curl nss
```

---
### まとめ
本当に簡単んなエラーでしたし、今で考えて見るとサポート終了に伴い当然
パッケージを提供するURLも変わる可能性が高かったのに当時は気づけませんでした。
勉強になりました。


---
### 参考資料
https://ateliee.com/archives/3946
gitでfatal: 'origin' does not appear to be a git repositoryと出た時の対処法

# 背景
git push した時の以下のようなエラーが出ました。

```
fatal: 'origin' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

```
調べたら参考資料がヒット！

```
git remote -v
```
で確認

# 解決法
これで解決しました。資料通りでしたね。
```
git remote add origin https://github****

```


# 資料
https://qiita.com/ktakita1011/items/3c16f0e0f7f3763c23d3
Tinker Board 2S をさわる

# 概要
Tinker Board 2S で 今話題沸騰中の X68000 エミュレータをビルドして動かしてみよう。

## 開封
ヒートシンクぇー
![FsqlnuwaEAE1hNm.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/3eea6e65-b5e7-7285-f322-b82a4f9d2d32.jpeg)

## インストール
MMC からはブートしないらしい。
USB ケーブルで Windows PC に接続すると、ドライブとして認識。
このドライブに OSイメージをダイレクトで書くらしい。
![FsqnlSjakAA1I1x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/c059f237-8b2a-9442-bbd8-d1435146d777.png)

OS イメージは [ASUSの公式ページ](https://tinker-board.asus.com/jp/download-list.html?product=tinker-board-2s) から、Tinker Board 2/2S Debian 10 V2.0.14 をダウンロードした。

書き込みは [balena Etcher](https://www.balena.io/etcher) で行う。
![FsqqeusaIAAeDzZ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/4a799c26-03fa-50de-e177-eb84f264f66f.png)

## 起動
HDMI をつなげて BOOT。
一瞬画像が読み込めない×マークが並ぶが待ってれば表示される。
- wifi をつなげる
- ターミナルを開いて ip a
- Windows PC から ssh
  - ID: linaro
  - PASSWORD: linaro

## ビルド環境
- make/g++ は最初から入ってる

## SDL2
[ここ](https://wiki.libsdl.org/SDL2/Installation#Linux.2FUnix) を参考に SDL2 をビルドする
- git も最初から入っているので、そのままコマンドを入れるだけ

### ALSA
最初にビルドした時は音が出なかった。
調べてみると SDL2 を configure をした時点で libasound がないと怒られてる。
> checking for libasound headers version >= 1.0.11... not present.

OSS は組み込まれるが、/dev/dsp がないので音は鳴らない。
なので libasound2-dev をインスコする。これで音も鳴るようになる。

### やったこと
~~~
sudo apt install libasound2-dev
git clone https://github.com/libsdl-org/SDL.git -b SDL2
cd SDL
mkdir build
cd build
../configure
make
sudo make install
~~~

## xkeropi のビルド
make するだけ

とりあえず動いた！
![Fsq7g85aQAIorPR.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/eceba862-2f63-da30-4f1b-3290c20dab52.jpeg)
React TutorialをベースにReact + TypeScript五目並べアプリの開発


# React チュートリアル

従来の`React`公式のチュートリアルはクラスコンポーネントで作成されていました。
実際は関数コンポーネントで作成するケースがほとんどで、公式チュートリアルを書き換える記事も多くありました。
現在ベータ版(英語のみ)ですが関数コンポーネントで作成する公式チュートリアルがあり、実際に作成してみました。
三目並べのプログラムで、コードも英語もそこまで難しくないです。

https://react.dev/learn/tutorial-tic-tac-toe

ただあくまでチュートリアルであり、気になる点もちらほら。
そこで三目並べ作成後に`React` + `TypeScript`にして、五目並べのプログラムに変更しました。
ここではざっくりと、三目並べと五目並べの説明と修正箇所を記載します。

## Introduction

- 製作者（私）
  - Web 系のスキルは業務ほぼ未経験（`Python`で簡単な`Flask`サーバーをたてる程度）。
  - `HTML` + `CSS` + `JavaScript`はググれば何とかなる（はず）。
  - `React`や`TypeScript`は自習で軽く触った程度。
- 製作意図
  - Web 系転職に必要な言語スキル習得のため。
  - 数ヶ月後に当時のスキルを把握するため。

## 概要

### チュートリアルの三目並べ

- 盤面は 3\*3
- O と X で盤面を埋める。
- ターンプレイヤーを表示。
- 勝者を表示。
- 前に戻る（所謂「ちょっと待った！」）。
- ◯✕ ゲームといった方が馴染み深い。

### 作成した五目並べの追加機能

- 盤面は 10\*10
- ● と ○ で盤面を埋める。

### ソースコードの修正内容

- `React` + `TypeScript`に変更。
- 盤面を設定で任意のサイズに変更。
- ファイル分割。
- ソースコードのリファクタリング。
  - ハードコーディングの解消。
  - `TypeScript`の型。
  - `JSDoc`の追加。
  - and so on.

## ソースコード

`React` + `TypeScript`で作成した五目並べは GitHub に公開しております。

https://github.com/kagami-tsukimura/react-gomoku

### 感想

クラスコンポーネントのチュートリアルと比較してコーディングしたため、可読性の向上を確認できました。
`React`面白いのですが書き方に慣れなくてもどかしい気持ちが拭えませんね。
とはいえ今回チュートリアルを書き換えたことで、言語理解が深まったのではないかと思います。
なお、チュートリアル〜五目並べ完成まで約 7 時間でした。
今月は応用情報技術者試験も控えているため、チュートリアルだけにする予定でしたが......
良い日曜日の過ごし方でした。
未経験新人エンジニアが最低限意識すると良さそうなこと（自戒）

## はじめに

既にQiitaにありふれた内容だとは思いますが、未経験でIT業界に入社した私が「もっとこうしておけばよかった」とか「もっと早く気づけば良かった」ということを最低限まとめてみました。



## 対象読者

- IT業界にプログラミングの経験がない状態で入る未経験新人エンジニアの方
- そういったエンジニアを教育するメンターの方

## 新人エンジニアが意識すると良さそうなこと

### プライベートの時間に勉強しよう

IT業界になんとなく入った人はプログラミングが好きじゃない人もいるかと思います。
ですが、プライベートの時間を使ってまったく勉強しないとなると技術力はなかなか上がりません。
同年代の学生時代からプログラミングをしている方は、プライベートの時間も当たり前にプログラムを書いています。
エンジニアになると決めたなら、そういった人たちと競っていかなければいけません。
しっかりプライベートの時間も使って勉強していきましょう。
エンジニアとしてやっていくと決めたならそういった **覚悟** を持ちましょう。

### ソースコードを読む努力をしよう

改修系のタスクを行うと既存のソースコードを読んで理解しなければならないのですが、最初はなにが書いてあるか理解できないと思います。
そういった時に先輩にすぐ質問するのではなく１度自分で読む努力をしましょう。
１行ずつ理解していきましょう。
最初は時間がかかると思いますが、徐々に早くなっていきます。大丈夫です。

### コピペはいいけどしっかり理解しよう

定番機能の実装とかだとネットにソースコードがある場合があります。
今だとchatGPTに質問をすればソースコードを教えてくれます。
その時に理解できていないのにも関わらず、コピペをして動いたから良しとするとするのはやめましょう。
しっかり理解してから使いましょう。

### 作業が止まったら先輩に相談しよう

作業が止まったら先輩に相談しましょう。
```わからない → 調べる → 少し理解する → やっぱわからない```
というフローで手が進んでいるときは正しい思考のプロセスだと思うので続けてください。
しかし、なにを調べればよいかわからない。自分がなにをしたいのかわからなくなった。という状況になったらすぐ先輩に相談しましょう。


### 自走できるようになろう

先ほど先輩に相談しようと書きましたが、なるべく早く自分で考えて実装までできるようなエンジニアになれるよう意識しましょう。
先輩の時間を使うということは、先輩のアウトプットを少なからず落とすことになります。（先輩はそれも業務なのですが）
なるべく早く自走できるエンジニアになれるように意識しましょう。
自走できるエンジニアになると、信頼されてどんどん難しいタスクを振ってくれるようになると思います。

### わからないことがたくさんあってもあまり落ち込むのはやめよう

わからないことがあるのは当たり前です。20年以上この業界にいる人もわからないことがあるのが当たり前と言っています。
なので自分が無能だと思って落ち込むのはやめましょう。
わからないことは調べてしっかり学んで成長していきましょう。

## おわりに

今年も新人のメンターをするので、後輩を最強のエンジニアにして私の仕事も全部やってもらおうと思います！


## 【番外編】教える側が意識したほうがよいこと（自戒）

### 自分の時間を使いすぎず、自走できるように教育しよう

自分の時間を教育に使い過ぎて自分の仕事が疎かになるのは本末転倒です。
最初にティーチングが多くなるのは仕方がないと思いますが、ずっと続けるとなると自分の業務時間を大きく割くことになってしまいます。
なるべく早い段階からコーチングをして自走してもらえるようになりましょう。
ペアプロとかも効果的ではあると思うんですが、やっぱり時間がかかりますよね。
ヒントを与えたらある程度は自分で考えてもらうようにしましょう。

### 優しく伝えるだけでなく時にはしっかり伝えよう

後輩に嫌われるのはきついですよね。
だからって後輩に気を遣って優しくするだけでは、後輩が成長しません。
ある程度緊張感はもって仕事をしてもらうようにしましょう。
強く伝えるのは伝えるほうも自分にストレスがかかると思いますが、そこは後輩のためです。頑張ってください。

### 自分より優秀になっても妬むのはやめよう

すごく優秀な後輩っていますよね。
最初はプログラムがわからない場合も、すごいスピードで成長する後輩。
どんどん自分に迫ってきて抜かれるのではないかと不安になることありますよね。
でもそんな時に後輩の成長を邪魔するようなことをするのはやめましょう。
ダサすぎます。
自分の教え方が上手かったと思うようにしてプライドを保ちましょう。
でも実際はそんなことはなく自分の努力が足りてないだけなのでもっと努力しましょう。
Active Directory 正常性試験スクリプト

お疲れ様です。キムです。

前回投稿したADサーバ構築の続きで
今回の投稿はActive Directoryの正常性試験の方法を投稿します。

ADの正常性を確認する方法
==================================================
<確認作業の流れ>

1. AD データベースの複製状況の確認
2. SYSVOL、NETLOGON 共有の確認
3. ドメイン コントローラーの正常性の確認
4. 各種イベント ログの確認


---
### 確認手順
#### ①AD データベースの複製状況の確認
コマンド プロンプトにて repadmin /showrepl コマンドを実行し、
Active Directory データベースの複製にエラーが無いことを確認します。
また、グローバル カタログ サーバーの場合は "DSA OPTIONS: IS_GC" という項目があることを確認します。

```
> repadmin /showrepl
```
出力結果一部例）
※Default-First-Site-Name¥[Hostname]


#### ②SYSVOL、NETLOGON 共有の確認
コマンド プロンプトにて net share コマンドを実行し、SYSVOL 及び NETLOGON が共有されているかを確認します。共有名に NETLOGON 及び SYSVOL が表示されていることで正常に共有できていると判断できます。
```
> net share
```
出力結果一部例）
※C:¥Windows¥SYSVOL¥[NetBIOS名]¥SCRPITS

・出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310719/e6d0d666-a8c6-73a5-b248-33f2c0d9b6f4.png)

---
#### ③ドメイン コントローラーの正常性の確認
コマンド プロンプトにて「dcdiag /v」コマンドを実行し、各テストにエラーが無く、"合格しました" と表示されることを確認します。
Advertising に合格していることで、ドメイン コントローラー、及びグローバル カタログとして正常に機能していると判断できます。

・出力結果一部例）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310719/9250ddce-365b-8b18-ab1f-c6c45932b703.png)

---

### 正常性試験コマンド
上記テストを一つづつ実施するのは、面倒なので下記のスクリプトを実施してメモ帳で確認します。
コマンドの実施方法はbatファイルに保存して実施します。※文字コードは「ANSI」に変更してください。（UTF-8は文字化け）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310719/81d2d2fb-cf08-7458-abc4-775f10c76da3.png)

```
rem ActiveDirectoryサーバ構築後の動作試験
set LOG_FILE=ActiveDirectory_%hostname%_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log
echo --- START : %DATE:~0,4%%DATE:~5,2%%DATE:~8,2%_%TIME:~0,2%:%TIME:~3,2% --->>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- ホスト名取得 --->>%USERPROFILE%\Desktop\%LOG_FILE%
hostname >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- IPアドレス取得 --->>%USERPROFILE%\Desktop\%LOG_FILE%
ipconfig /all >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- 共有フォルダ取得 --->>%USERPROFILE%\Desktop\%LOG_FILE%
net share >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- AD強制同期 --->>%USERPROFILE%\Desktop\%LOG_FILE%
repadmin /syncall /e >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- AD同期確認 --->>%USERPROFILE%\Desktop\%LOG_FILE%
repadmin /showrepl >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- FSMOサーバ確認 --->>%USERPROFILE%\Desktop\%LOG_FILE%
netdom query fsmo >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- AD正常性確認-A --->>%USERPROFILE%\Desktop\%LOG_FILE%
dcdiag /a >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- AD正常性確認-V --->>%USERPROFILE%\Desktop\%LOG_FILE%
dcdiag /v >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- AD正常性確認-E --->>%USERPROFILE%\Desktop\%LOG_FILE%
dcdiag /e >>%USERPROFILE%\Desktop\%LOG_FILE%
echo --- AD正常性確認-TEST-DNS --->>%USERPROFILE%\Desktop\%LOG_FILE%
dcdiag /TEST:DNS /V /E >>%USERPROFILE%\Desktop\%LOG_FILE% 
echo --- END   : %DATE:~0,4%%DATE:~5,2%%DATE:~8,2%_%TIME:~0,2%:%TIME:~3,2% --->>%USERPROFILE%\Desktop\%LOG_FILE%
rem 環境変数削除
set LOG_FILE=
```
実施したコマンド内容をメモ帳にエクスポートする簡単なコードです。取得されたログを確認しながら、テストに失敗したとかエラーが発生するところを確認し問題を解決します。
特に問題が無ければ全てのテストに合格しますので、これにて正常性試験は終了です。

---
### まとめ
今回は構築したADの正常性試験を確認する方法を投稿しました。
忘れないように日記みたいな感じで投稿しています。でも、本語に翻訳して投稿するのは結構手間がかかりますね。


では、引き続きよろしくお願いいたします。
[Windows11]ネットワーク上に保存したシステムイメージを使ってPCを復元する方法（エラー：ネットワークパスが見つかりません 0x80070035 を回避する方法）

# はじめに
メーカーに修理に出すために初期化したパソコンを元に戻すために、前もって別のパソコンにネットワークを通して「バックアップと復元(Windows 7)」で作成していたシステムイメージを使って復元しようとしたところ、


`ネットワークパスが見つかりません 0x80070035`


のエラーが出て苦戦したので最終的にどのようにしたかを残します。

# 前提
OS：Windows11
復元するドライブ：C
（CドライブがBitLockerで暗号化されている場合、コントロールパネルから前もってBitLockerを無効にしておいてください）

# 対処法
### その1

「`設定`」→「`システム`」→「`回復`」→「PCの起動をカスタマイズする」の「`今すぐ再起動`」

再起動すると青い画面が出てきます

### その２
「`トラブルシューティング`」→「`詳細オプション`」→「`イメージでシステムを回復`」（ない場合、「その他の修復オプション」を押すと出てきます）

「コンピューターイメージの再適用」画面が出現します

### その３
「このコンピューター上にシステムイメージが見つかりません」の警告が出てきたら「`キャンセル`」をクリック

「システムイメージを選択する」のラジオボタンを選択し「`次へ`」をクリック

「`詳細設定`」→「`ネットワーク上のシステムイメージを検索する`」→「ネットワークに接続しますか？」の警告画面で「`はい`」をクリック

システムイメージのある共有フォルダのパスを求められるので、WindowsImageBackupフォルダが入っているフォルダのパスを下記のように入れます。
`\\IPアドレス\共有フォルダ`


:::note alert
IPアドレスではなくPCの名前を入れると、ネットワークのパスが見つからないとのエラーが私の環境では出ました
:::

コンソール画面が開き、ユーザー名とパスワードの入力を求められるので

ユーザー名： システムイメージ保存先のIPアドレス\ユーザー名（例： 0.0.0.0\user_name）
パスワード： システムイメージ保存先のパソコンに上記ユーザー名でログインする際のパスワード

:::note info
ユーザー名とはC:Windows\Users の中にあるフォルダに付いている名前です（未検証）。
:::

一覧に検出されたシステムイメージの一覧が出るので、リストアしたいものをクリックして復元を待ちます。

私の場合、ここで新たにエラー：0x80070020が発生し、他のプロセスが使用中のため復元出来ないと出ましたが、イメージ保存先のパソコンを再起動することで解決しました。
（イメージファイルを使用中のプロセスはリソースモニタで調査可能）


https://johobase.com/identify-process-file-open-windows/




（もともとBitLockerが有効だった場合）
復元完了後にBitLockerが有効になっていませんという警告が出るので再起動後に改めてコントロールパネルから有効にします。

# さいごに
復元作業を始めてから完了するまでエラーの解決法が分からないために４、５時間かかりました。
このまま復元出来ないのではと思った時、復元が失敗した時のために備えて手動でファイルのコピーなどをしていて本当に良かったと感じました（結局使わずに済みましたが）。
皆さんも常日頃から念には念を入れてバックアップしましょう。
超個人的、PowershellとTerminal(Linux)のコマンドの違い

題名からしてわかりにくいのですが、要はWindowsとLinuxのコマンドがどういう風に違うのかまとめです。

毎度毎度の備忘録です。

ちなみにslコマンドはLinuxだとうまく使えない感じ...かな?　間違ってたらすみません（；∀；）

使用してるバージョンはPowershell core v7.3.0です

| Powershell | Terminal | 用法|
| --- | --- | --- |
| ls | ls -l | カレントディレクトリの内容確認 |
| cat | cat | 指定したファイルの確認 |
cd.. or cd .. | cd .. | 上位ディレクトリに戻る Linuxではスペース必須|
sl (/go/to/home) | (error) | |
Copy-Item  | copy | ファイルのコピー。Powershellではディレクトリは-Recurse オプションをつける
| ipconfig | ifconfig
Remove-Item | rm | ファイルまたはディレクトリ削除
## Powershellのみ

| command | |
| --- | --- 
clear | 表示をすべてリセット
alias設定を使い、Python コマンドで Python 3 が実行されるようにする

Macのターミナルのpythonコマンドをpython3にalias設定して、pythonと入力するとPython3が実行されるようにする。

# 一時的なaliasを作成したい場合
aliasコマンドを実行すると、現在のセッションでのみ有効なaliasが作成される。

```zsh
alias python='python3'
```

# 永続的なaliasを作成したい場合。
## 1. ~/.zshrcファイルにaliasを追加する
aliasを永続的に保存するには、設定ファイルに追加する必要がある。
```zsh
echo "alias python='python3'" >> ~/.zshrc

```
このコマンドは、設定ファイル（.zshrc）の末尾に新しいaliasを追加する。

## 2. 設定ファイルを更新するために、sourceコマンドを使用して、変更を再読み込みする
```zsh
source ~/.zshrc
```
この方法で新しいエイリアスがすぐに適用される。
ターミナルを閉じて開き直しても新しいエイリアスが適用されている。


## ＜補足＞
ターミナルでコマンドを実行する際、aliasは通常のコマンドよりも優先される。
python2を実行する必要がある場合は、'python2'と入力すればよい。
Apple M2 Pro でHomebrew インストール

## 概要&PCスペック
homebrewインストール時にPATHが通っておらず、brewコマンドの実行できなかったため
自分用の備忘録としてインストール方法を載せる。
少しでも誰かの助けになれば幸いです。

PCについて
MacBook Pro (2023/1月発売)
OS：macOS(Ventura 13.3)
チップ：Apple M2 Pro
シェル：zsh

初回起動時のAppleID連携以外のセッティングは何もしていない。

## 1. CommandLineTools(CLT)のインストール
homebrewのインストールにCommandLineToolsが必要になるため。
App StoreからXcodeをインストールすれば、CLTも一緒にインストールされる。

私の場合、Xcodeが必要だったためApp StoreからXcodeをインストールしたが、
とりあえず、CLTだけ必要な場合は、以下のコマンドをターミナルで実行すると良いらしい。
（Xcodeは7GB以上あるためインストールすると時間がかかる）
```
xcode-select --install
```
インストールが終わったら、以下を実行してアクティブなディベロッパディレクトリが出力されれば問題ない。
```
xcode-select -p
```
出力例：/Library/Developer/CommandLineTools

## Homebrewのインストール

[Homebrewのサイト](https://brew.sh/index_ja)のインストールに記載されているコマンドを実行

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
しばらく待つとHomebrewのインストール自体は完了する。

## HomebrewのPATHを通す

コマンド実行後の出力の中に以下のWarningメッセージがあるはず
```
Warning: /opt/homebrew/bin is not in yor PATH.
    Instructions on how to configure your shell for Homebrew
    can be found in the 'Next steps' section below.
```
Next steps以下にこのWarningに対処する方法が出力されているので、指示に従う。
私の場合は、以下２つのコマンド実行でした。
```
(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/○○○○/.zprofile
```
○○○○はホームディレクトリ名
```
eval "$(/opt/homebrew/bin/brew shellenv)";
```
これで、２個目のコマンドと同じものが記載された.zprofileファイルがホームディレクトリ配下に作成され、コマンドのPATHが通り、brewコマンドが実行できるはず。
※２個目のコマンドは実行しなくてもいいが、その場合はターミナルを再起動させる必要がある（と勝手に推測してる）。

## おまけ
HomebrewのPATHについては「HomebrewのPATHを通す」で記載したコマンドを実行しないで、
ホームディレクトリ配下の.zshrc（ない場合は作成して）に以下を追加するだけでも良い。
```
export PATH=/opt/homebrew/bin:$PATH
```
追加後は、ターミナルを立ち上げ直すか、以下コマンドで追加した内容を読み込ませることでPATHが追加される。
```
source .zshrc
```

※PATHの確認方法
```
echo $PATH | sed -e "s/:/\n/g"
```
sed -e "s/:/\n/g"は任意だが、PATH毎に改行して出力されるので見やすい。


## 参考
[CommandLineToolsとXcode](https://qiita.com/payreikit/items/4bb0f863afc7b56d0809)
[.zshrcの設定例（設定内容の説明コメント付き）](https://qiita.com/d-dai/items/d7f329b7d82e2165dab3)
VSCodeのHTTPサーバーを起動するための拡張機能「Live Server」

# Visual Studio CodeにはHTTPサーバーを起動するための「Live Server」という拡張機能がある

「Live Server」をインストールすると、Visual Studio Code内でWebサイトを作成した際に、HTMLやJavaScript、CSSなどの静的ファイルをローカルサーバーで表示することができる。

ファイルの変更を保存すると自動的にページが更新されるので便利。

# 「Live Server」のダウンロード方法

- Visual Studio Codeを開く
- 「Extensions」アイコンをクリック
- 検索ボックスに「Live Server」と入力し、拡張機能を検索
- 「Live Server」をクリックしてインストールする
- ファイルを開き、右下の「Go Live」アイコンをクリックする

 # 「Live Server」の使い方
ファイルを開き、右下の「Go Live」アイコンをクリックすると「Live Server」を起動する。また、自動的にブラウザが起動する。

「Live Server」が既に起動しているときは、Explorer→ファイル名を右クリック→Open with Live Serverでも起動できる。
Httpie: ChatGPT API の使い方

## スクリプト

```bash:http_fujisan.sh
http https://api.openai.com/v1/chat/completions \
  'Authorization: Bearer sk-11*******' \
  @in01.json > out01.json
#
jq .choices[0].message out01.json
```

```json:in01.json
{
  "model": "gpt-3.5-turbo",
  "messages": [{"role": "user", "content": "富士山の高さは"}],
  "max_tokens": 800,
  "temperature": 0
}
```

## 実行結果

```text
$ ./http_fujisan.sh 
{
  "role": "assistant",
  "content": "3776メートルです。"
}
```
初心者備忘録1 チームでのgithub2

前回の記事でブランチを増やす場合の手順を踏んだ。

次に開発した内容はリリース前のコードがあるブランチ（developブランチ）にマージしてもらう申請をリーダーやPdMにします。

これをPR（Pull Request）プルリクと言います。

開発したコードは必ずPRを出してリーダーやPdMに確認をしてもらいます。
これをコードレビューと言います。

レビューをしてもらい問題なければ、developブランチにマージしてもらう事ができ開発タスク終了となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3309860/2f65c8e8-fe7d-6d02-f6f2-bfc0c1609428.png)

まずはPRをしてみます。
GithubのPull Requestを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3309860/9f36623f-3404-db40-1605-527b45adaa79.png)

New pull requestを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3309860/f37ee118-a29b-1d83-233d-96ac7fcfccaf.png)


Comparing changesの下に記載されている箇所の
baseをdevelopにし、Compareを作業したブランチを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3309860/acc97f4a-c952-8b09-0e84-97af7dba1199.png)

下のコミットが自分の作業ブランチになっているのを確認してCreate pull requestを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3309860/0e595665-8fb1-5fdf-1173-66449370cd1c.png)

右のReviewsにはレビューしてほしい人の名前
その下のAssigneesには自分の名前を入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3309860/dcc87f50-6efb-bc1f-5922-11dff5f0a9ae.png)

Writeには実装した内容や実装でやったことを箇条書きなどで簡易的に説明。
この内容の書き方については別で記述予定。

書き終わったらCreate pull requestを押す。

下記画面が表示されたら問題なくPRが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3309860/ec0c2df1-175a-d952-f040-801c59e1c01a.png)


PRの作成ができたらレビューしたい人に連絡をしましょう。


レビューを依頼する前に下記には気を付けましょう。
1.セルフコードレビューを行う。
　不要なコメントアウト、不要なコードが残っていないか。
　作成したのは自分なので第三者目線でみるように心がける。
2.レビュー者を補助できるようコメントを書く。
　複雑な場所はPRやコード上にコメントを残す。
DDD初心者でも仲良くなりたい ~ドメインサービス編~

## 仕様オブジェクト

仕様はあるオブジェクトがある評価基準に達しているかを判定するオブジェクト。

- オブジェクトの評価処理にはオブジェクトのメソッドとして定義されるには似つかわしくないものが存在する
- 複雑な評価の手順はアプリケーションサービスに記述されてしまうことが多い
- オブジェクトの評価はドメインの重要なルールのため、アプリケーションサービスに記述されることは問題である

## 良くないとされる例
### リポジトリを持つアプリケーション上で評価を行う
```アプリケーションサービス.php
class ApplicationService
{
    private BookRepository $bookRepository;

    public function save(Book $book)
    {
        $storedBooks = $this->bookRepository->getAll();
        foreach ($storedBooks as $storedBook) {
            if ($storedBook->name == $book->name) {
                throw new Exception('既に登録済みの書籍です');
            } 
        }
        $this->bookRepository->save($book);
    }
}
```
既に登録されている名前の書籍は登録できないというルールは、ドメイン知識である。
=>アプリケーションサービスにドメインのルールに基づくロジックを記述すると、ドメインオブジェクトは何も語らず、ドメインの重要なルールはサービスの至る所に記述されるようになってしまう。大前提として、ドメインのルールはドメインオブジェクトに定義されるべき。

### エンティティがリポジトリを受け取り、評価を行う
```エンティティ.php
class Entity
{
    private Book $book;

    public function isSave(BookRepository $bookRepository)
    {
        $storedBooks = $this->bookRepository->getAll();
        foreach ($storedBooks as $storedBook) {
            if ($storedBook->name == $book->name) {
                throw new Exception('既に登録済みの書籍です');
            }
        }

        return $this->book;
    }
}
```
=>リポジトリはそもそもドメイン由来のものではないため、エンティティがドメインモデルの表現に徹していないことになる。エンティティや値オブジェクトがドメインモデルの表現に専念するにはリポジトリを操作することを可能な限り避ける必要がある。


## 推奨される例
### 評価はアプリケーションサービスで、仕様クラスを呼び出して行う
```仕様クラス.php
class Specification
{
    private BookRepository $bookRepository;

    public function __construct(BookRepository $bookRepository){
        $this->bookRepository = $bookRepository;
    }

    public function isSatisfied(Book $book) :bool
    {
        $storedBooks = $this->bookRepository->getAll();
        foreach ($storedBooks as $storedBook) {
            if ($storedBook->name == $book->name) {
                return false;
            } 
        };
        return true;
    }
}
```
この仕様クラスをアプリケーションサービスで呼び出して、評価に使う。
```アプリケーションサービス.php
class ApplicationService
{
    public function __construct(Specification $specification){
        $this->specification = $specification;
    }

    public function save(Book $book)
    {
        if (!$this->specification) {
            throw new Exception('既に登録済みの書籍です');
        } 
        $this->bookRepository->save($book);
    }
}
```
=>仕様はオブジェクトの評価のみを行う。複雑な評価手順をオブジェクトに埋させずに切り出すことで、その趣旨が明確になっている。

もし、オブジェクトの評価処理をオブジェクト自身に実装すると、オブジェクトの趣旨はぼやけてしまい、オブジェクトが何のために存在し何を為すのかが見えづらくなる。
[C#]リストから指定の型にキャストできる要素を取り出すにはOfTypeメソッドを使おうという話

# はじめに
本記事はC#においてリストから指定の型にキャストできる要素を取り出す方法をまとめます。

# やりたいこと
基底クラスのリストから指定した派生クラスの型の要素を取り出す場合を考えてみます。
といっても具体例がないとイメージがわかないと思うので、以下のようにAnimal(動物)クラス、Vertebrate(セキツイ動物)クラス、Invertebrate(無セキツイ動物)クラスの関連がある際に、基底クラス(Animalクラス)型のリストから派生クラス(Vertebrateクラス)型の要素を取り出したい場合を考えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452292/c12f47b3-4ebe-67de-8419-69f28f00e3dd.png)

# 最初に思いついた実装案
十分に実現方法を調べない状態で筆者が実装したコードは以下でした。
```csharp
// 動物一覧を作成
var animals = new List<Animal>();
animals.Add(new Vertebrate(){Name = "人間"});
animals.Add(new Vertebrate(){Name = "犬"});
animals.Add(new Vertebrate(){Name = "猫"});
animals.Add(new Invertebrate(){Name = "イカ"});
animals.Add(new Invertebrate(){Name = "タコ"});

// セキツイ動物を取得
var vertebrates = animals.Where(animal => animal is Vertebrate).Select(animal => (Vertebrate)animal);
```
WhereメソッドでVertebrate型の要素を抽出し、抽出した要素をSelectメソッドでVertebrate型にキャストするといったコードになります。
コードを書いた時点から、Linq文が長いので、もっと簡潔に記載できる方法はないかなと思っていました。
調べてみると[OfTypeメソッド](https://learn.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.oftype?view=net-7.0)でやりたいことがより簡潔に書けることがわかりました。

# OfTypeメソッドを使う場合
[OfTypeメソッド](https://learn.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.oftype?view=net-7.0)はIEnumerableのシーケンス要素から指定した型にキャストできる要素のみを取り出すメソッドになります。
まさに今回やりたいことを実現するのに適したメソッドになります。
前章のコードをOfTypeメソッドを利用するように書き換えると以下のようになります。
```csharp
// 動物一覧を作成
var animals = new List<Animal>();
animals.Add(new Vertebrate(){Name = "人間"});
animals.Add(new Vertebrate(){Name = "犬"});
animals.Add(new Vertebrate(){Name = "猫"});
animals.Add(new Invertebrate(){Name = "イカ"});
animals.Add(new Invertebrate(){Name = "タコ"});

// セキツイ動物を取得
// OfTypeメソッドを使うことで変数animalsからVertebrate型の要素を取り出していることが一目でわかるようになる
var vertebrates = animals.OfType<Vertebrate>();
```
OfTypeメソッドを使うことでLinq文が短くなり、変数animalsからVertebrate型の要素を取り出していることが一目で分かるようになりました。
やはり、何かを実装する際にはより適切な実現方法がないかに常に関心を持ち、調べることが重要だなと再認識しました。

# まとめ
本記事はC#においてリストから指定の型にキャストできる要素を取り出す方法をまとめました。
始めは、WhereメソッドとSelectメソッドを組み合わせて実現していましたが、OfTypeメソッドを使うことでコードを見ただけですぐにリストから指定の型にキャストできる要素を取り出しているのだと分かるようになりました。
やはり、より最適な実装方法に常に関心を持ち、調べることが重要だと再認識しました。この考えはこれからも持ち続けていきたいです。
Vircadiaが提供するドキュメントとソースコード

Vircadiaの技術的要素を説明する前に、Vircadiaが提供するドキュメントとソースコードについて紹介したいと思います。
なお、紹介する内容は、私がVircadiaを触ってみたときの情報であり、Vircadia団体が提供する公式の内容に加え、私自身の主観的な要素も含まれます。
Vircadiaアプリケーションに興味を持つ方向けに何かの参照にしていただければ幸いです。

## Vircadiaが提供するドキュメントとソースコード
### Vircadiaが提供するドキュメント
３種類の観点で提供されています。
私自身、Vircadiaを触ると同時にローカル環境にVircadiaサービスを起動してみたいという想いがあったため、Vircadiaの環境をローカルで構築するにあたり、利用者向けのマニュアルからどのような機能が提供されているのか把握するために閲覧しました。
その後、ソフトウェアの構成を理解するために、Vircadiaフレームワークのソフトウェアスタックについて、さらに、CLIコマンドの理解を進めました。
参照したURLを以下に記載します。

**1\.Vircadiaの利用者向けの内容**
Vircadiaが提供する環境を用いたメタバース空間の構築やアバタ利用について案内されています。

https://docs.vircadia.com/

**2\.Vircadiaの開発者向けの内容（その１）**
VircadiaフレームワークのソフトウェアスタックやCLIレベルでのコマンドについて案内されています。

https://docs.vircadia.dev/

**3\.Vircadiaの開発者向けの内容（その２）**
コンテンツの作成者と開発者向けとして、Vircadiaメタバースの空間を制御するためのAPIについて案内されています。

https://apidocs.vircadia.dev/

### Vircadiaが公開しているソースコード
Vircadia団体が公開するソースコードは以下のGithubで閲覧することができます。
私が、ローカル環境にVircadiaを構築した際に必要としたモジュール類は全て以下のGithubからダウンロードができました。
各レポジトリとその構成について紹介します。

https://github.com/vircadia

#### 各レポジトリの構成
レポジトリは、大枠5つの分類で区分けができそうです。
**1\.Vircadia本体およびコアモジュール関連**

https://github.com/vircadia/vircadia

https://github.com/vircadia/vircadia-metaverse

**2\.Vircadia本体が必要とするライプリ**

https://github.com/vircadia/vircadia-web-sdk

https://github.com/vircadia/vircadia-unity-sdk

**3\.Vircadia Web関連**

https://github.com/vircadia/vircadia-web

https://github.com/vircadia/metaverse-dashboard

**4\.Vircadiaマニュアル関連**

https://github.com/vircadia/vircadia-docs-sphinx

https://github.com/vircadia/vircadia-dev-docs

https://github.com/vircadia/vircadia-user-docs

**5\.その他、グロックチェーン（ドラフト版？）ライブライ関連**

https://github.com/vircadia/hifi-blockchain

#### ローカル環境構築時の参照レポジトリ
上記URLからローカル環境構築時に必要としたレポジトリについて紹介します。
※ こちらは次回紹介予定。只今まとめ中

## 次回は
メタバース環境構築に必要となる全てのVircadiaサービスをローカルPC上で起動するための情報を配信していきます。
まずは、各種サービスおよびソフトウェアスタックについて紹介する予定です。
Astro + Angular で ng cli を使えるようにする

# はじめに

[@analogjs/astro-angular](https://www.npmjs.com/package/@analogjs/astro-angular) の初期状態では ng cli が入っていなかったので、使えるようにしてみました。

# 手順

## 1. Astro で Angular を使えるようにします

https://qiita.com/nishitaku/items/3f888da5a695f7b44cc4

## 2. ng cliをインストールします

```console
npm i -D @angular/cli
```

## 3. angular.json ファイルを作成します

angular.jsonファイルを作成して、ng cliを騙します。

あわせて generate component セマンティクスのオプションも設定します。

```json
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "components": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "",
      "architect": {}
    }
  },
  "schematics": {
    "@schematics/angular:component": {
      "path": "src/components",
      "standalone": true
    }
  }
}
```

### オプションの説明

<dl>
<dt>"path": "src/components"
<dd>隠し(?)オプションです。コンポーネントファイルの生成先です。これがないと、src/app/~~~ に生成されます。
<dt>"standalone": true
<dd>コンポーネントをモジュール非依存形式で生成します。
</dl>

# 使ってみる

いつものようにコンポーネントを生成できるようになりました。

```console
% npx ng g c HelloWorld
CREATE src/components/hello-world/hello-world.component.css (0 bytes)
CREATE src/components/hello-world/hello-world.component.html (26 bytes)
CREATE src/components/hello-world/hello-world.component.spec.ts (623 bytes)
CREATE src/components/hello-world/hello-world.component.ts (312 bytes)
```

# 成果物

作ったものは、こちらに置きました。

https://github.com/sengokyu/astro-angular-experience
ArchTag を使って ArchTest だけを実行する

# 環境
- ArchUnit 1.0.1

# ArchTest だけを実行したい

私のプロジェクトではコーディング規約を ArchTest として実装し、ユニットテストと共に実行できるようにしています。
ただ、テストケースをすべて実行すると割と時間がかかります。
規約チェックのために ArchTest だけを選択的に実行したい。

そこで、試しに JUnit の `@Tag` アノテーションを付けてみましたが動作しませんでした。
原因は調べていませんが、たぶん `@Tag` は `@Test` アノテーションが付いているものだけを実行対象としてリストアップするんでしょう。
調べると、`@ArchTag` アノテーションという `@Tag` アノテーションに相当するものが ArchUnit に用意されていたため、これを使って実現しました。

# 実装

## ArchTest に ArchTag アノテーションを付ける
まず ArchTest を収録している TestCase に `@ArchTag` を付けます。
```java:FooTest.java

@AnalyzeClasses(
    packages = {"io.github.takeyoda"},
    importOptions = ImportOption.DoNotIncludeTests.class)
@ArchTag("ArchTest")
class FooTest {
  @ArchTest
  public static final ArchRule SOME_TEST = classes().that()...;
}
```

## build.gradle に専用のタスクを追加
`build.gradle` に ArchTest だけを実行するタスクを追加します。
```gradle:build.gradle
tasks.register('archTest', Test) {
  testLogging {
    events 'passed', 'skipped', 'failed'
  }
  useJUnitPlatform {
    includeTags 'ArchTest'
  }
}
```

## 実行例
追加したタスクを実行します。
```shell-session
$ ./gradlew archtest
```

# まとめ
`@ArchTag` アノテーションを使って ArchUnit のテストケースをカテゴライズする方法を紹介しました。
Jacascriptのイベントリスナーのthisとeventについて

イベントリスナー内で event と this の両方を使用することができる。
ただし、event と this は異なる目的で使用される。

event はイベントオブジェクトで、イベントに関する情報（クリックされた要素、イベントのタイプ、発生した時刻など）を提供する。
イベントオブジェクトはイベントリスナーの引数として渡される。


一方、this はイベントリスナーが追加された要素を参照する。
これにより、イベントが発生した要素に対して操作を実行したり、要素のプロパティにアクセスしたりできる。


通常、イベントリスナー（イベントハンドラ）内での event.currentTarget は this と一致する。event.currentTarget はイベントリスナーがアタッチされた要素（DOM ノード）を参照し、this も同じ要素を参照する。
【まとめ】これまで作成したRailsアプリ

# 概要
これまで作成したRailsアプリをまとめています。

# これまで作成したRailsアプリ
https://qiita.com/shoya15/items/d85ef84f564439f5494c

https://qiita.com/shoya15/items/95eab6376bc2e574f4ce
[備忘録]シークレット変数を使ってGitHub Actionsで機密情報を利用する

### はじめに
機密情報をGitHub Actionsで使う方法を調べてもなかなか出てこなくて手こずったので、今回行った方法を備忘録として記録しておきたい。

### シークレット変数を設定してPythonファイルで利用する

#### Settingsでの操作
まず、GitHubの任意のレポジトリを開き、[Settings]→[Secrets and Variables]→[Actions]→[New repository secret]を選択する。
次に、NameとSecret(APIキーなどの機密情報)を入力して登録する。

#### ワークフローでの操作(ymlファイル)

```
- name: Run XXX
        env:
          API_KEY: ${{ secrets.API_KEY }} # secretsに登録した環境変数
        run:
          python/XXX.py #XXX.pyを実行
```
#### Pythonファイルでの操作

```
import os
# secretsに登録した環境変数の呼び出し
API_KEY = os.environ.get("API_KEY")
```
チーム開発Git操作関連をまとめてみた

# はじめに
2022年にある企業でチーム開発を体験し、その楽しさを実感できたので、自分なりに復習の意味を込めてまとめてみる。
## 手順
早速手順を書いていく。
### GitHubのアカウントを作成する
リンク：https://github.com/

`登録 => SignIn => Register`

### GitHub上にリポジトリを作成する
`リポジトリ`は、ファイルやディレクトリを入れて保存しておく貯蔵庫のようなもの。

`リモートリポジトリ`は、サーバー上に配置して、複数の人と共有できるもの。

`ローカルリポジトリ`は、ユーザーごとに配置されるもの、（手元でいじれる。）

チームで開発する時は、Privateがおすすめかもしれん。（チームのルールに従うのが筋）

### Gitの初期設定をする

ユーザー名とメールアドレスの設定を実施していく。

"First-name Family-name"　→ 自分のユーザー名を入力する
"username@example.com" → 自分のメールアドレスを入力する

```
$ git config --global user.name "First-name Family-name"
$ git config --global user.email "username@example.com"
```
### 個人アクセストークンを作成する

こんな感じになるのでは
```
$ git clone https://github.com/username/repository.git
Cloning into 'repository'...
Username for 'https://github.com': username
Password for 'https://username@github.com':
remote: Password authentication is temporarily disabled as part of a brownout. Please use a personal access token instead.
remote: Please see https://github.blog/2020-07-30-token-authentication-requirements-for-api-and-git-operations/ for more information.
fatal: unable to access 'https://github.com/username/repository.git/': The requested URL returned error: 403
```

詳細：[GitHubがパスワード認証を廃止するらしいので](https://qiita.com/shiro01/items/e886aa1e4beb404f9038)
## チームメンバーとリポジトリの共有

:::note info
ここからが主題！
:::

### Owner側（リポジトリに招待を送る人）
共有したいリポジトリまで行く。
URLでいうと、［github.com/アカウント名/ファイル名］のところで、`Settings > Collaborators»`を選択。
ユーザーのアカウント名orユーザーのメールアドレスを入力していく。
`Add Collaborator`を選択。

招待したい人に確認してみる。

### Collaborator側（リポジトリに招待が送られる人）
メールを確認する。

メールでリンクを踏んで、`Accept Invitation`をクリックする。

完了

## プロジェクトのクローンをしていく。
vscodeなんでもEditorを開いて、ターミナルを出す。
コマンドで下をうつ！

```
$ git clone [リポジトリパス]
```
`<>code`ボタン のところを押して、`HTTPS`or`SSH`で`git clone`を実行していく。

:::note info
GitHub的にはHTTPSを推奨しているみたい。
:::

[詳細](https://zenn.dev/nameless_sn/articles/the_differences_between_https_and_ssh)


## Gitのissue設定
### なぜissueか？
あれをやらないといけない。これをやらないといけないという感じでタスクが山積みになってくる。

そんな状況で`GitHub上で`タスクを立てて`プルリク`と同時にタスクをバッサバッサとこなしていく。

爽快

### 体系的に使い方を知っていく
リポジトリに進み左上のissueを選択する。

![e8b9b7c3-a375-4659-b658-60f240ee558a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627753/02693029-ee2a-5840-0264-acd8ba5583ca.png)

`Newissue`を選択。タイトルを入力して、bodyに詳細を入力する。
![ダウンロード.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627753/f53aa623-f433-6f8d-22a8-5324fcd15bcf.jpeg)


【おすすめ】チェックボックスとかをタップして、作るのおすすめ！

こんな感じ
- [ ] タスク1
- [x] タスク2


記入がある程度済んだら、右横の担当者とかLabelとかを選択して、誰に何のタスクを割り振るとかタスクの種類（バグなのかとか）を設定する。
![スクリーンショット 2023-04-02 17.07.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627753/a9804b54-948d-5fbb-c85f-7261b52c2263.png)

完了！

ブランチを切って作業をしていく。

作業が完了したら、プッシュをして、プルリクを作成！

:::note info
この時、issueのタスク番号を載せてあげると、紐づいてかなり見応えが増す。
:::

## Tips
### SSH公開鍵認証

・手元のvscode上でフォルダを作成し移動
・GitHub上で公開鍵を設定する。
→　GitHub右上のアイコンからSettingsを選択し、SSH and GPG keyを選択する。
titleを記入して、公開鍵を登録する。

参照：[GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~](https://qiita.com/shizuma/items/2b2f873a0034839e47ce)
【Rust】UTF-8 BOMについて

## はじめに

RustでのUTF-8 BOMについて調べました。

## ファイル読込

以下の様なUTF-8 BOM形式のテキストファイルを開くとします。

```test.txt
Hello
```

このファイルを開くと先頭に奇妙な文字が付いています。

```rs
// test.txtを読み込む
let content: String = fs::read_to_string("test.txt")?;
// charのベクタに変換
let chars: Vec<char> = content.chars().collect();
println!("{:?}", chars);
```

```:実行結果
['\u{feff}', 'H', 'e', 'l', 'l', 'o']
```

## `\u{feff}`

`\u{feff}`はUTF-8 BOM(ファイルの先頭にある`0xEF 0xBB 0xBF`の3バイト)をchar形式に変換した文字になります。
この文字を整数型に変換すると65279(16進数で0xFEFF)になり
バイト配列に変換すると、上記の3バイトになります。

```rs
let c = '\u{feff}';
c as u32; // 65279
c.to_string().as_bytes(); // [0xEF, 0xBB, 0xBF]
```

## UTF-8 BOMを除く関数

「文字列の先頭1文字がBOMならそれを除く」という処理は`Peekable`を使えば簡単に実装できます。
`Peekable`とはイテレータの一種ですが、先に進めずに現在の値を確認することができます。
UTF-8 BOMを除く関数は以下の様になります。

```rs
fn remove_utf8_bom(s: String) -> String {
    let mut chars = s.chars().peekable();
    if let Some('\u{feff}') = chars.peek() {
        chars.next();
    }
    chars.collect()
}
```



## 参考文献

https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E9%A0%86%E3%83%9E%E3%83%BC%E3%82%AF

https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html
Curl: ChatGPT API の使い方

## 参考ページ
[Create chat completion](https://platform.openai.com/docs/api-reference/chat/create?lang=curl)

## スクリプト

```bash:go_fujisan.sh
API_KEY="sk-****************'
curl https://api.openai.com/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer '$API_KEY \
  -d '{
  "model": "gpt-3.5-turbo",
  "messages": [{"role": "user", "content": "富士山の高さは"}]
}' > out01.json
#
jq .choices[0].message out01.json
```

## 実行結果

```text
$ ./go_fujisan.sh 
{
  "role": "assistant",
  "content": "3776メートルです。"
}
```

## 関連情報
[Httpie: ChatGPT API の使い方](https://qiita.com/ekzemplaro/items/23957732b233f6b35f94)
[Node.js: ChatGPT API の使い方 (https)](https://qiita.com/ekzemplaro/items/cd9310725fa45011f51e)
[Node.js: ChatGPT API の使い方 (axios)](https://qiita.com/ekzemplaro/items/02ce0741ee67972c009e)
[Node.js: ChatGPT API の使い方 (node-fetch)](https://qiita.com/ekzemplaro/items/73d3ef67dff4ea23ca10)
[Deno: ChatGPT API の使い方](https://qiita.com/ekzemplaro/items/2a176a3473a480c5136f)
[Julia: ChatGPT API の使い方](https://qiita.com/ekzemplaro/items/8ad42a4f29c87a8379e6)
最新の電話 2023 で SMARTFI オートバイ エラー リーダーを確認する

近年、FIバイクの修理やエラー読み取り機のチェックが注目されています。市場には、より用途の広い FI モーターサイクル エラー リーダーが数多く出回っています。電話でのオートバイ エラー読み取りソフトウェアは、オートバイ エラー リーダーを購入する場合と比較して、ユーザーがコストを最適化するのに役立つ新しい開発です。
 SMARTFI電話でオートバイのエラーを読み取り、削除するソフトウェアの紹介
 電話でオートバイのエラーを読み取って削除するソフトウェアは、電話で直接車を修理するのに役立つ発明です。
 メーカーの AUTOSHOP は、この傾向に追いつき、2022 年に SMART FI オートバイ診断デバイスを発売しました。デバイスはコンパクトで便利です。このデバイスは、自動車の故障の診断と分析、および修理構成のマッピングに集中的に適用されます。
 FI SMART FI カーエラー リーダーは、Biuetooth 接続 - ワイヤレス接続のおかげで、その機能が高く評価されています。 SMART FI には、車両に接続するためのハードウェアと、CH Play または App Store から無料でインストールできる SMART FI 診断アプリが含まれます。 SMART FIを利用するメリット
 一般的な自動車メーカーの診断、読み取り、トラブルシューティングをサポート
  FI モーターサイクル フォールト リーダーを使用すると、ユーザーはエンジン システム、アンチロック ブレーキ システムなどの完全な車両システムを診断できます。
SMARTTOOL 2エラー除去リーダーを参照してください https://smarttool2.vn/
記事を参照してください：https://smarttool2.vn/review-smarfi-may-doc-loi-xe-may-tren-dien-thoai.html
Material3のタブ選択位置を強制的に戻す【Kotlin】

## 内容
この記事ではMaterial3を利用した[タブ](https://m3.material.io/components/tabs/overview)をコード上で操作する方法を書いています。
今回は、QRスキャンと画像からQRを読み込む機能を入れたタブを作成しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527236/bc9216fb-9eb4-1ec3-4183-21f22e2c12b2.jpeg" width=200>
このタブは下記のような動作を想定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527236/92dc2401-c687-bebb-e1fc-8b97d7897507.png)
上記フローにおいて画像読み込みをクリック後に画像選択をキャンセルした場合に`スキャン`にタブ位置が戻るようにします。この設定を行わない場合`画像読み込み`にタブの選択状況がなったままスキャン画面が表示されてしまいます。


## コード
```kotlin
override fun onRestart() {
    super.onRestart()
    val tabLayout = binding.tabLayout
    tabLayout.getTabAt(0)?.select()
}
```
このコードはアクティビティ内に書いています。タブには左から0->1->2と番号が振られているのでこの仕組みを利用して元に戻します。onRestartで処理を行う理由として画像選択時に画像選択のアクティビティが生成されているためです。
文字列型の時間データを数値型に変換する方法 JavaScript・PHP・Ruby

# JavaScriptの場合
```javascript
const timeString = "12:30:45";
const timeParts = timeString.split(":");
const hours = parseInt(timeParts[0]);
const minutes = parseInt(timeParts[1]);
const seconds = parseInt(timeParts[2]);
const totalSeconds = hours * 3600 + minutes * 60 + seconds;
console.log(totalSeconds); // Output: 45045

```

## JavaScriptのコード解説：

1行目で、変換したい文字列型の時間データ "12:30:45" を定数`timeString`に代入します。
2行目で、文字列を区切り文字 ":" で分割し、配列`timeParts`に格納します。
3行目から5行目で、各配列要素を数値型に変換し、それぞれ変数 `hours`, `minutes`,`seconds` に代入します。
6行目で、時間を秒数に変換し、変数`totalSeconds`に代入します。
7行目で、結果をコンソールに出力します。

# PHPの場合

```php
$timeString = "12:30:45";
$timeParts = explode(":", $timeString);
$hours = intval($timeParts[0]);
$minutes = intval($timeParts[1]);
$seconds = intval($timeParts[2]);
$totalSeconds = $hours * 3600 + $minutes * 60 + $seconds;
echo $totalSeconds; // Output: 45045

```

## PHPのコード解説：

1行目で、変換したい文字列型の時間データ "12:30:45" を変数`$timeString`に代入します。
2行目で、文字列を区切り文字 ":" で分割し、配列 $timeParts に格納します。
3行目から5行目で、各配列要素を整数型に変換し、それぞれ変数 `$hours`, `$minutes`, `$seconds` に代入します。
6行目で、時間を秒数に変換し、変数 `$totalSeconds` に代入します。
7行目で、結果を出力します。

# Rubyの場合
```ruby
time_string = "12:30:45"
time_parts = time_string.split(":")
hours = time_parts[0].to_i
minutes = time_parts[1].to_i
seconds = time_parts[2].to_i
total_seconds = hours * 3600 + minutes * 60 + seconds
puts total_seconds # Output: 45045
```

## Rubyのコード解説：

1行目で、変換したい文字列型の時間データ "12:30:45" を変数 `time_string` に代入します。
2行目で、文字列を区切り文字 ":" で分割し、配列 `time_parts` に格納します。
3行目から5行目で、各配列要素を整数型に変換し、それぞれ変数 `hours`, `minutes`, `seconds` に代入します。
6行目で、時間を秒数に変換し、変数 `total_seconds` に代入します。
7行目で、結果を出力します。


誰に需要があるかはわかりませんが、自分がわかんなかったので、覚書