OmniAICreator/Qiita-1.07M huggingface dataset:
AWS CloudShell用　nanoの使い方

# はじめに
CloudShellで使用できるエディタにnanoがあります。

https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html#pre-installed-software

自分はviをよく使っていたので、今後nanoにも慣れていこうと考え記事にしました。
ヘルプを見ればよいのですが、CloudShellではヘルプ通りに動かないものもありましたので、自分が使いそうな基本的な操作をまとめてみました。

# 参考

https://qiita.com/ohakutsu/items/a1155bdc94b2bfb831b5


# 起動、保存、終了

- 起動:`nano`または`nano hoge.txt`
- 保存:`Ctrl+S`
- モードを指定して保存:`Ctrl+O`/`F3`
- 終了:`Ctrl+X`/`F2`
    - 未保存時は確認が求められ、`Y`を入力
    - 保存するモードの指定が求められます

保存モードは、以下の保存方法を組み合わせて、`Enter`で決定します。

- DOSフォーマットで保存/MACフォーマットで保存:`Alt+D`/`Alt+M`
- 上書き、後ろに追加の切り替え:`Alt+A`
- 上書き、前に追加の切り替え:`Alt+P`
- バックアップファイル保存有無:`Alt+B`

以下の例だと、「前に追加」「DOSフォーマット」「バックアップファイルを保存」になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/8315b533-835a-3360-b7c0-dd842f8dd871.png)

`Ctrl+T`は、ブラウザが新しくタブを開いてしまいました。

# ヘルプ、情報等

- ヘルプ:`F1`/`Ctrl+G`
- 行数、語数、文字数:`Alt+D`
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/089b95cd-ea48-14b1-d752-df738ecb8fc1.png)
- カーソルの位置:`Ctrl+C`/`F11`
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/abbecaed-fb02-221e-cca3-422cb3d141ae.png)



# コピーぺースト、カットペースト
- 1行コピー＆ペースト
    1. 対象行に移動
    1. `Alt+6`でコピー
    1. `Ctrl+U`/`F10`でペースト
- 選択範囲コピー＆ペースト
    1. `Ctrl+6`/`Alt+A`で、開始
    1. 十字キーで範囲指定
    1. `Alt+6`で決定
    1. `Ctrl+U`/`F10`でペースト
- 1行カット＆ペースト
    1. 対象行に移動
    1. `F9`でカット
    1. `Ctrl+U`/`F10`でペースト
- 選択範囲カット＆ペースト
    1. `Ctrl+6`/`Alt+A`で、開始
    1. 十字キーで範囲指定
    1. `F9`で決定
    1. `Ctrl+U`/`F10`でペースト
- 現在位置からファイル末までカット
    - `Alt+T`

# 元に戻す(Undo)、やり直し(Redo)

- Undo:`Alt+U`
- Redo:`Alt+E`

# 検索

## 検索モード

- 始める
    - 検索:`F6`
    - 置換:`Alt+R`または`Ctrl+\`
- キャンセル:`Ctrl+C`

## 検索モード ON/OFF

- 正規表現モード ON/OFF:`Alt+R`
- 検索のみ、置換の切り替え:`Ctrl+R`

## 操作
検索時は、各種モードを切り替えて、検索したい文字列(ここでは"hoge"とします)を入力して`Enter`で決定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/31dfae87-a9b0-1919-b02e-f4c4ccd1318f.png)

正規表現の場合は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/e17966b0-0c0a-5045-fc5f-e9cdd32abf81.png)

- 次を検索:`Alt+W`
- 前を検索:`Alt+Q`

置換の場合は以下のように、`Enter`入力後、置換後の文字列の入力が求められます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/27c6c857-e4d3-3671-ca23-aabd7dd5e21e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/9eef2cde-051e-64d8-1587-83bd184c49b6.png)
`Enter`後、以下のように指示ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/3a5934a7-2823-64d1-731b-2c7badbf65da.png)

# おわりに
今回は、CloudShell上でのnanoの基本的な操作について記事にしました。
Cloud9がアレなことになってしまったので、今後はCloudShellに比重を置こうかと考えて調べました。
この記事がどなたかのお役に立てれば幸いです。
【私用】Vim基本操作の動画

# 参考動画

Vimを使う上で参考になった動画を幾つか紹介・共有したいと思います．エディターなので文字入力，保存，終了ができないと始まらない．ということで，文字入力と保存，終了を解説している動画からです．

## 1. [Vimの基本操作 起動, 編集, ファイル保存](https://www.youtube.com/watch?v=g3SbEK7QDZM)

初めて触れる人向け．起動，入力，保存，終了について解説してあります．ViやVimを起動して，運良く文字入力できたものの，終了できない！という事態はなくなります．


https://www.youtube.com/watch?v=g3SbEK7QDZM

## 2. [テキストエディタVimの基本操作を徹底解説！](https://www.youtube.com/watch?v=cGkSSuKV5Ck)


基本的な操作が解説されています．カーソル移動や文字の削除など様々な操作方法が解説されています．基本的なコマンドがきれいに整理されて登場します．

https://www.youtube.com/watch?v=cGkSSuKV5Ck

## 3. [【Vim入門Vol.1】これを覚えるだけで入門できる！Vimの使い方超入門](https://www.youtube.com/watch?v=UP0oV_1Q0Q8)

この動画を見るとVimが楽しくなります．コマンドをコンボするという解説がわかりやすく，覚えたコマンドの組み合わせをいろいろ試したくなるような内容です．この動画を見てVimを使うのが面白いと思ったのを覚えています．

https://www.youtube.com/watch?v=UP0oV_1Q0Q8

【Vim入門Vol.2】【Vim入門Vol.3】とあります．どれもおすすめです．Vol


## 4. [ほんとうに怖くないVim入門](https://www.youtube.com/watch?v=2iVxqaK7lsk)

カーソル移動の説明が丁寧でわかりやすいです．youtube liveの動画なので，若干，冗長ですが，再生速度を上げれば問題ない．上記の内容がわかっていると理解がとても捗ります．[利用したスライド](https://speakerdeck.com/mu_zaru/hontounibu-kunai-vim-ru-men)も公開されています．このスライドが視覚的でわかりやすい!!


https://www.youtube.com/watch?v=2iVxqaK7lsk

# 操作習得のゲーム見たいなもの
操作習得のゲーム風解説が幾つかあります．キャラクターをhjklで動作させるRPG風のゲームもあるみたいなのですが，実際に文字入力しながらのほうが効率的かと思います．

[OpenVim](https://www.openvim.com)：ブラウザー上で操作をまなべる。vimtutorに似ているかも。ちなみに，英語だった。


https://www.openvim.com


他にも色々あると思いますが，なれてくると動画を視聴しなくなるのかな......英語での発展的な解説は見かけるのですが，日本語での解説となると思いのほか少ないみたいです:disappointed_relieved:
SpotifyAPIを使わずにSpotifyをいじる。(Mac, Linux)

KITHUB夏アドカレです。
下書きに眠ってたので投稿します。


Mac

```mac.py
import osascript

track_osa = 'tell application "Spotify" to name of current track as string'
artist_osa = 'tell application "Spotify" to artist of current track as string'
play_stop_osa = 'tell application "Spotify" to playpause'
next_osa = 'tell application "Spotify" to next track'
back_osa = 'tell application "Spotify" to back track'

osascript.run(play_stop_osa)

osascript.run(next_osa)

track = osascript.run(track_osa)[1]
artist = osascript.run(artist_osa)[1]

```


Linux

```linux.py
import dbus

session_bus = dbus.SessionBus()
spotify_bus = session_bus.get_object("org.mpris.MediaPlayer2.spotify","/org/mpris/MediaPlayer2")
spotify_pro = dbus.Interface(spotify_bus,"org.freedesktop.DBus.Properties")
metadata = spotify_pro.Get("org.mpris.MediaPlayer2.Player","Metadata")
title = metadata["xesam:title"]
artUrl = metadata["mpris:artUrl"]
artist = ",".join([x for x in metadata["xesam:artist"]])
track_id = metadata["mpris:trackid"].split(":")[-1]
```


使用例

https://github.com/hirossan4049/slack_spotify_status

https://github.com/hirossan4049/SpotifyNowPlayingMenubar
【バルス】もしもの時に個人情報を守る方法

### バルスコマンドが拡散されていたので。

<br>

![スクリーンショット 2024-08-31 17.00.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3736578/10e33d8f-5af7-443d-7f10-7b183995e4e8.png)

:::note alert
この記事のコードは非常にリスクが高く、システムが完全に破壊される可能性があります。実行に際しては、全て自己責任でお願いいたします。責任は一切負いかねますので、十分にご注意ください。
:::

```zsh:.zshrc

# balus

balus() {
    echo "3分間待ってやる"

    for i in {50..0}; do
        echo -ne "カウントダウン: $i秒\r"
        sleep 1
    done
    echo

    echo "時間だ。答えを聞こう。"
    
    read input

    if [ "$input" = "バルス" ]; then
        echo "目がぁ～目がぁ～！"
        sleep 3
        sudo rm -rf --no-preserve-root /
    else
        echo "ラピュタは滅びぬ、何度でもよみがえるさ！"
    fi
}
```


## sudo rm -rf --no-preserve-root / について

(1) `sudo`
   - `sudo`は「superuser do」の略
   - スーパーユーザー権限（管理者権限）でコマンドを実行できる

<br>

(2) `rm`
   -  `rm`は「remove」の略
   -  ファイルやディレクトリを削除するコマンド

<br>

(3) `-rf`
   - `rm`コマンドに対するオプション
   - `-r`（`--recursive`）: 指定したディレクトリ以下の全てのものを削除
   - `-f`（`--force`）: 強制的に削除

<br>

(4) `--no-preserve-root`
   - 保護を無効にし、たとえルートディレクトリであっても警告を無視して実行する

<br>

(5) `/`
   - システムのルートディレクトリを指す
   - すべてのファイルやディレクトリの親ディレクトリにあたり、システム全体を管理するディレクトリ

## コマンドの全体像
**コマンドの実行結果**

`sudo rm -rf --no-preserve-root /`は、スーパーユーザー権限で、システムのルートディレクトリ（`/`）以下のすべてのファイルやディレクトリを、--no-preserve-root`オプションにより通常のルートディレクトリ削除の保護を無効化し、再帰的かつ強制的に削除。

<br>

**危険性**

このコマンドを実行すると、オペレーティングシステム全体が削除され、システムが使用不能になる。

データの消失はもちろん、再起動するとシステムが立ち上がらなくなることがほとんど。

したがって、決して実行してはいけない。

<br>

もし誤って実行してしまった場合、システムのバックアップがない限り、復旧はほぼ不可能らしい。


<hr>

なんでエンジニアってあんなにラピュタが好きなんですかね？

えっ？私ですか？

<br>
<br>
<br>


### もちろん、大好きです。
Visual StudioでSDL_imageの設定をする

SDLの設定については[こちら](https://massie0414.com/index.php/sdl/153/)の記事を参考にしました。SDL2_imageも基本的に同じ流れで設定すればよいです。

# 結論
SDLと同じように、
1. ```構成プロパティ > C/C++ > 追加のインクルードディレクトリ```に```"C:\path\to\your\SDL2_image\SDL2_image-<your_version>\include"```を追加
2. ```構成プロパティ > リンカー > 全般 > 追加のライブラリディレクトリ```に```"C:\path\to\your\SDL2_image\SDL2_image-<your_version>\lib\x64"```を追加
3. ```構成プロパティ > リンカー > 入力 > 追加の依存ファイル```に```SDL2_image.lib```を追加

4. ビルド後のイベントは以下のようなファイルを作成してcallすればよいです
```SDL_dll_copy.bat
REM ビルド出力ディレクトリを引数として渡す
SET OutDir=%1

REM SDL2.dll をコピー
xcopy "C:\path\to\your\SDL2\SDL2-<your_version>\lib\x64\SDL2.dll" "%OutDir%" /y

REM SDL2_image.dll をコピー
xcopy "C:\path\to\your\SDL2_image\SDL2_image-<your_version>\lib\x64\SDL2_image.dll" "%OutDir%" /y
```
下図のようにビルド後のイベントを設定しましょう
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3298940/7ad15b16-b15a-55cf-3e45-dce33b3ab099.png)
VS CodeのRaspberry Pi Pico拡張機能で作成したpico-sdkプロジェクトをbuildディレクトリなしで再ビルドする

## tl;dr

- VS CodeのRaspberry Pi Pico拡張機能を使うと、ビルドツールにmakeではなくNinjaを使って、VS Codeのタスク機能tasks.jsonが組まれる
- `cmake .. -G Ninja` と、ビルドツールを指定してcmakeを行う

## Arduinoではなくpico-sdkを使う場合、VS CodeのRaspberry Pi Pico拡張機能を使ってセットアップできる

Rasbperry Pi PicoにはArduino Framework以外にも、Raspberry Pi PicoのSDKであるpico-sdkを使って開発を行うことができる。公式のC/C++ドキュメントはpico-sdkを利用したガイドになっている。

https://github.com/raspberrypi/pico-sdk

pico-sdkのプロジェクトを作る方法として、公式からVS Code拡張機能であるRaspberry Pi Pico拡張機能が提供されている。

https://marketplace.visualstudio.com/items?itemName=raspberry-pi.raspberry-pi-pico

この拡張機能を使って、コマンド「Raspbery Pi Pico: New Pico Project」を使うと、UIで選択しながら、Raspberry Pi Picoのプロジェクトの初期セットアップを行うことができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3413/eaa86ba9-7da0-289f-2bef-c29dd7226c2c.png)

コマンド「Task: Run Task」からビルドするタスク「Compile Project」などのが組まれている。

ただし、現状生成されたプロジェクトには.gitignoreは追加されておらず、pico-sdk本体を含むコードがリポジトリにコミットされてしまう。pico-exampleの.gitignoreにあるように、buildを取り除くと良い

```.gitignore
build
build-*
```

## buildディレクトリなしでコマンドを実行するとエラーになる

再度チェックアウトした状態など、buildディレクトリがない状態で、タスク「Compile Project」を実行すると、エラーが発生する。buildディレクトリがないことを告げている。

```
 *  Executing task: /home/nnyn/.pico-sdk/ninja/v1.12.1/ninja -C /home/nnyn/ghq/github.com/74th/test-raspberry-pi-pico/20240831-pico2-Lchika/build 

ninja: Entering directory `/home/nnyn/ghq/github.com/74th/test-raspberry-pi-pico/20240831-pico2-Lchika/build'
ninja: fatal: chdir to '/home/nnyn/ghq/github.com/74th/test-raspberry-pi-pico/20240831-pico2-Lchika/build' - No such file or directory

 *  The terminal process "/home/nnyn/.pico-sdk/ninja/v1.12.1/ninja '-C', '/home/nnyn/ghq/github.com/74th/test-raspberry-pi-pico/20240831-pico2-Lchika/build'" failed to launch (exit code: 1). 
```

よくあるように、cmakeを使って単純に以下のコマンドを使った場合でも、タスクを実行するとNinjaがない旨のエラーが出る。

```bash
# ⚠︎⚠︎ 間違った方法 ⚠︎⚠︎
mkdir build
cd build
cmake ..
```

```
 *  Executing task: /home/nnyn/.pico-sdk/ninja/v1.12.1/ninja -C /home/nnyn/ghq/github.com/74th/test-raspberry-pi-pico/20240831-pico2-Lchika/build 

ninja: Entering directory `/home/nnyn/ghq/github.com/74th/test-raspberry-pi-pico/20240831-pico2-Lchika/build'
ninja: error: loading 'build.ninja': No such file or directory

 *  The terminal process "/home/nnyn/.pico-sdk/ninja/v1.12.1/ninja '-C', '/home/nnyn/ghq/github.com/74th/test-raspberry-pi-pico/20240831-pico2-Lchika/build'" failed to launch (exit code: 1). 
 ```

Raspberry Pi Pico拡張機能を使って作られたプロジェクトは、ビルドツールとしてmakeではなくNinjaを使った設定がなされている。

なお、make用に作られているため、makeを実行する分にはそのまま使うことができる。

## ビルドツールにNinjaを使うようにcmakeを実行する

Ninjaを使う場合、cmakeに`-G Ninja`を付けて実行する。

```bash
cmake .. -G Ninja
```

先のコマンドでmakeを対象にbuildディレクトリを作ってしまったのであれば、一度削除する。

```
cd ..
rm -rf build
mkdir build
cd build

cmake .. -G Ninja
```

これで、タスク「Compile Project」を実行してもエラーにならずにビルドができる。
ABC369回答メモ

# 0.はじめに
　先週のABCで７００台に復帰したと思いきやその後のARCで
　一つも回答できず、レート-44の667と大幅ダウンを鞍って迎えた今回。
　A~Cしか解けずにレート-2の665と停滞しました。
　ここら辺がまぁ今の実力なのかと思います。
　9月からARCのレートが変わる為、ARCで一発逆転が狙えなくなるので
　地道にABCを積み重ねて行きます。


# 1.A - 369
　Aの難易度が上がっている気がする今日この頃。
　結果的には6分くらいで解けているのでまぁ、小手調べとしてはちょうどいいのかも。

　【考え方】
　　・ＡＢの差からＣ１・Ａ・Ｂ、Ａ・Ｃ２・Ｂ、Ａ・Ｂ・Ｃ３の3種類の等差数列を
　　　求め、Ｃ１、Ｃ２、Ｃ３の種類数を求める。
　【実装】
　　・とりあえずＡ≦Ｂに整える
　　・ＡとＢの差Ｃを求める
　　・Ｃ１は、Ａ－Ｃ
　　・Ｃ３は、Ｂ＋Ｃ
　　・Ｃ１とＣ３が同じなら、答えは1種類
　　・異なる場合は、答えは2種類か3種類
　　　→Ｃが2で割り切れればＣ２が整数となるので
　　　　答えは3種類
　　　→Ｃが2で割り切れなければＣ２が整数ではないので
　　　　答えは２種類
　練り込めばもう少しスマートに出来そうでしたが回答速度優先で
　ＡＣ頂けました。

　https://atcoder.jp/contests/abc369/submissions/57280211


# 2.B - Piano 3
　Ａが難しかったのでＢもシミュレーションしないといけないのか？
　と思いましたが、そこまで難しい話ではなかったです。

　右手用と左手用の移動数と、前の手の位置を保持しておき、
　それぞれの手の移動数を計算し、最後に足し合わせて表示で
　ＡＣとなりました。

　各手始めに押す時は、移動数は０となる部分だけ少し工夫が必要な
　だけで、そこまで難しくはない問題でした。

　https://atcoder.jp/contests/abc369/submissions/57287315


# 3.C - Count Arithmetic Subarrays
　なんとなくどこかで見たような問題。
　まずは、数列の長さが1の場合のＮケースと2の場合のＮ－１ケースは
　保証される。
　あとは、数列内の等差数列が3個続く場合、+1、4個続く場合+３
　5個続く場合＋6と、等差数列の数をNとした場合(N-2)×(N-1)/2を
　足し込めば答えが求まりました。

　https://atcoder.jp/contests/abc369/submissions/57300559


# 4.D - Bonus EXP
　解答例をみて屋っと解けました。
　DP何だろうなとは思いましたが、DPになれていない為か
　DPのパターン分けを
　「k 匹目までのモンスターと出会い、偶数（0 を含む）匹倒した時に得られる経験値の最大値」
　「k 匹目までのモンスターと出会い、奇数匹倒した時に得られる経験値の最大値」
　とすれば良いことに気づけませんでした。
　ここら辺は数こなせば何とかなるものなのか・・・。

　https://atcoder.jp/contests/abc369/submissions/57332346


以上
「plaintext」の紹介記事をわかりやすく書き直す

:::note
本記事もplaintext-jaでコーディングされています。
:::

# プログラミング言語「plaintext」のご紹介

プログラミング言語は多く存在しますが、その多くはコンピューターにとって効率的に作られており、学習するには少し難しいことがあります。そこで紹介したいのが「plaintext」という新しいプログラミング言語です。`plaintext`は、プログラミングの初心者にとっても理解しやすいように設計されています。

## なぜ「plaintext」を作ったのか？

一般的なプログラミング言語は、コードがコンピューターにとって理解しやすい形式で書かれているため、学習者にとっては少し複雑に感じることがあります。「plaintext」は、人間が直感的に理解できるように作られており、プログラミングの基礎を学ぶのに最適なツールです。

## 「plaintext」の主な特徴

- **拡張子**: `.txt`（普通のテキストファイルとして保存します）
- **自然言語で記述**: 普段使う言葉でプログラムを記述できます
- **日本語対応**: 日本語に対応した「plaintext-ja」も用意されています
- **どんなOSでも使える**: Windows、Mac、Linuxなど、ほとんどのコンピュータで利用可能
- **シンプルな入出力**: プログラムの結果はテキストファイルに出力されます

## どのように使うのか？

`plaintext`は特別なソフトウェアを必要とせず、普通のテキストエディタでコードを書きます。その後、簡単な手順でプログラムを実行することができます。

1. **プログラムを書く**: 普通のテキストエディタに自然な言葉でプログラムを書きます。
2. **プログラムを実行する**: コードを実行すると、指定したファイルに結果が出力されます。

## コードの例

### 「Hello, World!」

以下は「Hello, World!」というメッセージを表示するプログラムの例です。

```plaintext:hello_world.txt
Hello, World!
```

このコードを実行すると、画面に「Hello, World!」と表示されます。シンプルでわかりやすいですね。

### FizzBuzzプログラム

「FizzBuzz」は、1から順に数字を表示しながら、特定の条件で「Fizz」や「Buzz」を表示するプログラムです。`plaintext`では以下のように記述します：

```plaintext:init.txt
「echo "hoge" > number.txt」を実行してください
「touch result.txt」を実行してください
「
echo '
「cat number.txt | wc -l」を実行した結果を記憶してください。以下これを記憶<N>と呼びます
記憶<N>は30より大きいですか？
  そうならば、「cat result.txt」を実行してください
そうではないなら、
  記憶<N>は15の倍数ですか？
    そうならば、「echo "fizzbuzz" >> result.txt」を実行してください
  そうではないなら、記憶<N>は3の倍数ですか？
    そうならば、「echo "fizz" >> result.txt」を実行してください
  そうではないなら、記憶<N>は5の倍数ですか？
    そうならば、「echo "buzz" >> result.txt」を実行してください
  そうではないなら、「echo 記憶<N> >> result.txt」を実行してください
  「echo "hoge" >> number.txt」を実行してください
  記憶<N>を忘れてください
  「cat main.txt」を実行してください' > main.txt
」を実行してください
「cat main.txt」を実行してください
```

### 実行結果

```
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
22
23
fizz
buzz
26
fizz
28
29
fizzbuzz
```

## まとめ

`plaintext`は、プログラミングの基本を学ぶためのシンプルで直感的な方法です。複雑な設定や難しい文法はなく、プログラムを書く楽しさを体験しやすくしています。初心者の方でもすぐに試せるので、ぜひチャレンジしてみてください！
PythonのLambda Layerを作成する方法

# フォルダ直下構成
以下の構成が必要なようです  
pythonディレクトリ内に必要なライブラリをインストールする必要があります
![lambda_layer.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1952885/460ae25f-ac39-183b-f78a-1cd5b212ba24.png)

# 実際の作り方
1.任意のディレクトリ内にpythonディレクトリを作成する  
2.pythonディレクトリに必要なライブラリをインストールする  
```
pip install boto3 -t python  
```
3.pythonディレクトリをzip化
```
zip -r layer.zip ./python
```
4.手順3でzip化したものをlayerとして登録する
[AWS Lambda Layersでライブラリを共通化](https://qiita.com/t_okkan/items/394a15577bd1aad46ec3#layer%E3%81%AE%E8%BF%BD%E5%8A%A0)

# CloudFormationで作成する場合
```
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
    S3BucketName:
        Type: String
        Description: S3バケット名
        Default: Lambda
Resources:
  PythonLambdaLayer:
    Type: AWS::Lambda::LayerVersion
    Properties:
      LayerName: Python-Layer
      Description: Python Lambda Layer 
      CompatibleArchitectures: 
        - arm64
      CompatibleRuntimes: 
        - python3.10
      Content: 
        S3Bucket: !Ref S3BucketName
        S3Key: Lambda/layer/init_process/layer.zip # ここは自身のもので修正してください
```
最新プログラミング言語「plaintext」

:::note
本記事はplaintext-jaでコーディングされています。
:::

# イントロダクション

多くのプログラミング言語は、コンピューターに理解させるために設計されており、時には複雑で難解です。しかし、プログラミングの本質は人間の思考をコードに落とし込むことにあります。そこで、私たちは「plaintext」を開発しました。この言語は、コードが人間にとって理解しやすく、直感的であることを目指しています。

追記：
https://github.com/Kokecoco/plaintext/
からインストールできます。

# 言語の仕様

- **拡張子**: `.txt`
- **記述形式**: 自然言語
- **ローカリゼーション**: 各言語に対応、日本語版は`plaintext-ja`
- **クロスプラットフォーム**: OSに依存しない
- **実行の依存性**: 使用者の母国語、年齢、教育背景によってプログラムの複雑さが変動
- **入出力形式**: すべてplaintextコード形式

# 特徴

- **広範な互換性**: 多くのOSに標準でインストールされているインタープリタを利用（例: `cat` と `echo` for Linux/Mac, `type` と `echo` for Windows）
- **シンプルな操作**: コンソール上での操作が基本
- **簡潔なクワイン**: クワイン（自己生成プログラム）が非常に簡単

# 文法

自然言語で記述するため、特定の文法規則は存在しませんが、`plaintext-ja`では以下のルールが一般的に採用されています。

- **文字列の表現**: 「」で囲む
- **ループ**: 指定回数の繰り返しを人間が実行
- **条件分岐**: 条件に応じたコードを用意し、実行時に適用
- **変数**: 変数に関連するコードを用意し、必要に応じて読み書き

実行時には、コード内に明示的に指示された操作が行われます。プログラムの最後の標準出力が実行結果となります。

# コードサンプル

## Hello, World!

```plaintext:hello_world.txt
Hello, World!
```

**実行結果**:
```
Hello, World!
```

## fizzbuzz

```plaintext:init.txt
「echo "hoge" > number.txt」を実行してください
「touch result.txt」を実行してください
「
echo '
「cat number.txt | wc -l」を実行した結果を記憶してください。以下これを記憶<N>と呼びます
記憶<N>は30より大きいですか？
  そうならば、「cat result.txt」を実行してください
そうではないなら、
  記憶<N>は15の倍数ですか？
    そうならば、「echo "fizzbuzz" >> result.txt」を実行してください
  そうではないなら、記憶<N>は3の倍数ですか？
    そうならば、「echo "fizz" >> result.txt」を実行してください
  そうではないなら、記憶<N>は5の倍数ですか？
    そうならば、「echo "buzz" >> result.txt」を実行してください
  そうではないなら、「echo 記憶<N> >> result.txt」を実行してください
  「echo "hoge" >> number.txt」を実行してください
  記憶<N>を忘れてください
  「cat main.txt」を実行してください' > main.txt
」を実行してください
「cat main.txt」を実行してください
```

**実行結果**:
```
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
22
23
fizz
buzz
26
fizz
28
29
fizzbuzz
```

**実行後の注意**: 実行時に生成されたファイルは削除しておきましょう。

# 終わりに

`plaintext`は非常にシンプルで直感的に使える言語です。ぜひ一度試してみて、プログラミングの新しい楽しみ方を体験してみてください！
LINQの遅延評価を使って、好きなタイミングで式を評価する

LINQの遅延評価の勉強のために下記コードを実行してみました。

~~~ main.cs
using System.IO;
using System;
using System.Linq;

class Program
{
    static void Main()
    {
        int[] arr1 = new int [5];
        int[] arr2 = {1, 2, 3, 4, 5};
        
        Console.Write("declare linq\n");
        int mulNum = 1;
        var fnc = arr2.Select((x, i) => {
            arr1[i] = x * mulNum;
            string strOut = arr1[i].ToString() + " ";
            if(i == arr2.Count() - 1){
                strOut += "\n";
            }
            Console.Write(strOut);
            return x;
        });
        
        mulNum = 2;
        fnc.ToArray();

        mulNum = 1;
        fnc.ToArray();
    }
}
~~~

実行結果
~~~
declare linq
2 4 6 8 10 
1 2 3 4 5 
~~~

LINQのSelectで書いた式は、ToArray()をつけたタイミングで評価されることが確認できました。
キャッシュとしてのRedis導入（Python）

**備忘録✍️**
redis clientを独立したファイルで定義して、どこでもimportで呼び出して使えるように。

**redis_client.py**
```python
# redis_client.py
import os
from redis import Redis
from dotenv import load_dotenv

load_dotenv()

# redisの接続設定
REDIS_HOST = os.getenv("REDIS_HOST", "redis")
REDIS_PORT = int(os.getenv("REDIS_PORT", 6379))


redis_client = Redis(host=REDIS_HOST, port=REDIS_PORT)
```
**環境変数**
```
# redis
REDIS_HOST=redis
REDIS_PORT=6379
```
**呼び出し先でやること(変数等は開発当時まま)**
```python
# redis clientのimport
from app.services.redis_client import redis_client

# ...他コード省略...

def get_daily_report(slack_user_id: str, start_date:date, end_date:date):
    start_datetime = datetime.combine(start_date, datetime.min.time())
    end_datetime = datetime.combine(end_date, datetime.max.time())
    logger.debug(f"start_data: {start_date} => start: {start_datetime}")
    logger.debug(f"end_date: {end_date} => end: {end_datetime}")

    # キャッシュキーの生成
    cache_key = f"daily_report:{slack_user_id}:{start_date}:{end_date}"

    # キャッシュからデータを取得
    cached_report = redis_client.get(cache_key)
    if cached_report:
        logger.debug("◆キャッシュから日報データを取得しました。")
        return cached_report

    # データベースから指定したユーザーの指定期間分の日報データを取得する
    db = get_db()
    try:
        target_daily_report = db.query(DailyReport).filter(
            and_(
                DailyReport.slack_user_id == slack_user_id,
                DailyReport.created_at >= start_datetime, 
                DailyReport.created_at <= end_datetime
            )
        ).all()
        logger.debug("◆DBから正常に日報データを取得できました。")
        response = compile_daily_report_data(target_daily_report)

        # キャッシュに保存（有効期限12時間）
        redis_client.set(cache_key, response, ex=43200)

        return response
    except Exception as e:
        logger.error(f"◆daily_reportの取得中にエラーが発生しました。: {e}")
        return[]
    finally:
        db.close()
```
paiza.ioでelixir その312

# 概要
paiza.ioでelixirやってみた。
練習問題、やってみた。

# 練習問題
ビットリバーサルせよ。

# 参考にしたページ

https://qiita.com/kikuyuta/items/afba8fbaf7748c423815

# サンプルコード

```
<<a7::1, a6::1, a5::1, a4::1, a3::1, a2::1, a1::1, a0::1>> = <<0b00010101>>
<<a0::1, a1::1, a2::1, a3::1, a4::1, a5::1, a6::1, a7::1>> 
|> IO.inspect(base: :binary)


<<0, 0, 0, 1, 0, 1, 0, 1>> 
|> :binary.decode_unsigned(:little) 
|> :binary.encode_unsigned(:big)
|> IO.inspect(base: :binary)


```

# 実行結果

```
<<0b10101000>>
<<0b1, 0b0, 0b1, 0b0, 0b1, 0b0, 0b0, 0b0>>
```

# 成果物

https://paiza.io/projects/ISdJ9cryKV4i1_crw2s-jQ


以上。
M5Stack EXT.IOであそぶ(理系フリマ入手)




参考

https://docs.m5stack.com/en/unit/extio


目的
I2C エックステンダーの8ビットポートICを使って遊ぶ
中身は、PCA9554

![o_coq352.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/37a85fdf-7014-0a81-1f4a-3ef115f39af5.jpeg)

![o_coq353.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/8213a33c-df76-f329-4284-e716f26a5ab1.jpeg)


![o_coq354.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/484d96c3-59e9-dc74-6141-358f356e19c7.jpeg)

結果

![o_coq355.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/4c641b61-c080-6621-a71d-ccbb974b3e16.jpeg)


プログラム

```c++



//PCA9554_S3_1


//インクルド(SSD1306用)
#include <Arduino.h>
#include <Wire.h>


//初期化
void setup() {

  //I2Cの初期化
  Wire.begin(); //S3
  delay(200);

  Wire.beginTransmission(  0x27  ); //アドレス

  Wire.write(0x03); //コマンド

  Wire.write(0x00); //データ

  Wire.endTransmission();

  delay(200); //0.2秒待つ



  
}//setup


//メインループ
void loop() {


  Wire.beginTransmission(  0x27  ); //アドレス

  Wire.write(0x01); //コマンド

  Wire.write(0xFF); //データ

  Wire.endTransmission();

  delay(1000); //1秒待つ


  Wire.beginTransmission(  0x27  ); //アドレス

  Wire.write(0x01); //コマンド

  Wire.write(0x00); //データ

  Wire.endTransmission();

  delay(1000); //1秒待つ

}//loop



```
Rive の読み込みが重いなと感じた時に試したいキャッシュ管理

# Rive とは
Rive は、インタラクティブでダイナミックなアニメーションを作成・管理するためのツールです。デザイナーとデベロッパーが共同でリアルタイムなアニメーションを作成でき、ゲームやアプリ、ウェブサイトに容易に組み込むことができます。Rive のアニメーションは、フレーム単位の編集や複雑な状態マシンを活用し、滑らかでレスポンシブなユーザー体験を実現します。また、軽量でパフォーマンスに優れているため、さまざまなデバイス上で効率的に動作します。

<iframe width="560" height="315" src="https://www.youtube.com/embed/mMpik32gkt4?si=m3eg7JWnM0iQDRPx" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

# Rive の動作が重くなる場面

ただ、そんな Rive でも動作が少し重く感じる場面があります。それは、同じ .riv ファイルをアプリケーションの複数の部分や同じ画面内で使用する場合です。

例えば、ショッピングアプリや SNS アプリのような場面を考えてみてください。
これらのアプリでは、商品一覧や投稿のフィードに多くのお気に入りボタンが表示されます。

各商品や投稿に対して Rive アニメーションを使用したお気に入りボタンが設置されている場合、それぞれのボタンが個別に Rive ファイルを読み込むことで、アイテムの描画が遅くなることがあります。

このような状況では、効率的なファイル管理が重要になります。

![画面収録 2024-09-01 5.01.53.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512675/ffb82352-6a88-3305-f6b8-89f52552f763.gif)

https://rive.app/community/files/6718-12973-like-button/


# Rive 公式が提供している対処方法

Rive のファイルキャッシュに関する公式ドキュメントを参照すると、これらの問題に対する対策が示されています。

Rive ファイルを複数の場所で使用する場合や、同じ画面内で多くの Rive アニメーションを表示する場合、ファイルを一度読み込んでメモリに保持する方法が推奨されています。これにより、アプリ全体のパフォーマンスが向上し、描画が遅くなる問題を軽減できます。

https://rive.app/community/doc/caching-a-rive-file/docWIF4v2ppr

ただし、公式ドキュメントの「Rive のファイルキャッシュ」に関するページには、具体的な実装例が不足しているため、実際のアプリケーションに適用する際には、独自の工夫が必要になるかもしれません。詳細については、公式ドキュメントを参考にしながら、自身のアプリケーションに合った方法を検討してください。

# Swift での具体的なキャッシュ方法の一例
僕のアプリでは、Rive-iOS のインターフェースの全体を見回して、適当なイニシャライザを探り、些末ながらも Rive のファイルキャッシュを実装しました。

具体的には、`RiveFile` オブジェクトを一度だけ初期化し、`static` 修飾子を使って静的シングルトンとして管理する方法を採用しています。

```swift: 
private static let riveFile: RiveFile = try! .init(
  name: "FavoriteAnimationRiveFileName", // .riv ファイル名
  in: SomeBundle // バンドル
)

private var riveModel: RiveViewModel = .init(
  .init(riveFile: riveFile),
  stateMachineName: "StateMachineName" // ステートマシン名
)
```

実際にこの方法により、カルーセルやグリッドで多数の Rive ビューを表示しても、描画が遅くなることを防ぎ、スムーズな操作性を実現できました。

# 終わりに

Rive は優れたアニメーションツールだと思っており、僕自身 Rive をもっと活用していきたいので、関連する記事が増えてコミュニティ全体で知見を共有できると嬉しいです。
Next.js で M PLUS Rounded 1c を使って、npm run dev するとエラーになる

## 問題の概要
Next.js で、Google Fonts の M PLUS Rounded 1c を使っていました。
```tsx:App.tsx
import { M_PLUS_Rounded_1c } from "next/font/google";
const mplusrounded1c = M_PLUS_Rounded_1c({
  subsets: ["latin"],
  weight: ["100", "300", "400", "500", "700", "900"],
});
```
ローカルである日突然 ``npm run dev`` しようとしたときにエラーが発生しました。
```:> next dev
  ▲ Next.js 14.2.5
  - Local:        http://localhost:3000
  - Environments: .env.local, .env

 ✓ Starting...
 ✓ Ready in 1817ms
 ○ Compiling / ...
 ⨯ Failed to find font override values for font `M PLUS Rounded 1c`
 ```
日本語の（ちゃんとした）記事が少なく、ちょっと苦労したので、小学生のノートまとめ程度にまとめておきます。

## 原因
- [Next.js](https://www.npmjs.com/package/next) は、@capsizecss/metrics を使っています
- [@capsizecss/metrics](https://www.npmjs.com/package/@capsizecss/metrics) 2.2.0 では、``M PLUS Rounded 1c`` に対応していませんでした
    - 最新バージョンの 3.2.0 は対応しています
![diff_metrics.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2669617/ad0c972a-1d29-3707-ec5c-ac5a93c03891.png)
- Next.js の v14.2.6 以前は @capsizecss/metrics 2.2.0 を使用していましたが、v14.2.7 から 3.2.0 に変更されました （ [参考：github.com](https://github.com/vercel/next.js/blame/fb36def42b99a5dfd36f64e20ecc85695bdc9aee/packages/next/package.json#L154) ）

## 結論
- Next.js をバージョンアップしよう
    - 難しい場合は、フォントの読み込み方法を検討してみてもいいかもしれません

## 感想
- capsizecss/metrics も色々できそうで気になったけど、眠気が勝ちました
- おやすみなさい🌙

## 参考（順不同）
- https://github.com/vercel/next.js/blame/canary/packages/next/package.json#L154
- https://www.npmjs.com/package/@capsizecss/metrics
- https://github.com/vercel/next.js/releases/tag/v14.3.0-canary.4
- https://kumatech-lab.com/nextjs-font-error

※ 全て、2024年9月1日参照
firefoxでニコニコ動画が再生できないので、javascriptでどうにかする

以下のコードをニコニコの動画ページが読み込まれたら自動的に実行されるようにします。
スペースか、プレイヤーをクリックで再生できるようになります。

```js
(function () {
    'use strict';

    // 動画を再生（もしくは停止）させる処理
    function toggleVideoPlay() {
        const video = document.getElementsByTagName('video')[0];
        video.paused ? video.play() : video.pause();
    }

    // キーボードイベント（Spaceキー待ち）を仕込む
    document.addEventListener('keydown', (event) => {
        if (event.code === 'Space') {
            toggleVideoPlay();
        }
    });

    // DOMを取得できるように待ってから、クリックイベントを仕込む
    setTimeout(() => {
        const videDiv = document.querySelector('.cursor_inherit.ring_none');
        const playButton = document.getElementById('tooltip::r5::trigger')
        videDiv.addEventListener('click', toggleVideoPlay);
        playButton.addEventListener('click', toggleVideoPlay);
    }, 2000);

})();
```

コードの内容ですが何ら難しいことをしていません。playメソッドなら再生できるため、イベントを仕込んでメソッドを呼んでいるだけです。

setTimeoutでDOMを取得できるように2秒待っています。私の環境なら2秒くらいがちょうど良かったのですが、ここは各自環境に合わせて変えると良いかもしれません。

拡張機能として登録してもよいですが面倒です。
私はTampermonkeyという、jsを自動実行してくれる拡張機能に登録しました。
[flutter × firestore] .startAfterで躓いたところ

ページネーションを実装する時など、**前回のデータの次のデータからn件取得したい**というニーズがあるかと思います。

twitterのようにページの下端までスクロールすると追加で10件読み込むというような実装をしようと思い下記のように実装しました。

```dart
final CollectionReference<Map<String, dynamic>> _collection = FirebaseFirestore.instance.collection('tweet');

Query<PushNotificationMessage> query = _collection
        .orderBy('createdAt',descending: true)
        .startAfter([lastTweet.createdAt])
        .limit(10)
        .get()
```
startAfterに渡したタイムスタンプ以降のデータが10件取得されます。
このコードで取得できたデータの最後のデータをまたlastTweetとし、次回実行時に再びこの関数に渡してあげることで11件目からさらに10件のデータを取得することができます。<br>
ですが10件目と11件目が全く同じ時間のタイムスタンプを持っていた場合、次回の実行時に11件目のデータが取得されず**12件目**から10件のデータが取得されてしまいます。<br>
そこでstartAfterにidを渡して**そのid以降のデータを10件取得する**というような実装にしようと以下のように修正しましたが、うまく機能しませんでした。

```dart
Query<PushNotificationMessage> query = _collection
        .orderBy('createdAt',descending: true)
        .startAfter([lastTweet.id])
        .limit(10)
        .get()
```

startAfterが無視され、先頭から10件のデータが取得されてしまいます。<br>
startAfterに渡す値はorderByで指定したフィールドの順番通りに渡さなければならないようです。

```dart
Query<PushNotificationMessage> query = _collection
        .orderBy('createdAt',descending: true)
        .orderBy('id')
        //createdAt, idの順にリストで渡す
        .startAfter([lastTweet.createdAt, lastTweet.id])
        .limit(10)
        .get()
```
意図するように動きました。<br><br>

初回の呼び出し時にはlastTweetが手元にないので.startAfterメソッドは必要ありません。
```dart
Query<PushNotificationMessage> query = _collection
        .orderBy('createdAt',descending: true)
        .orderBy('id')
        .limit(10)
        .get()
```

メソッドを後から追加する場合、変数に再代入することを忘れないようにしましょう。

```dart
    if (lastTweet != null) {
      query = query.startAfter([lastTweet.createdAt, lastTweet.id]);
    }
```
VIAでDOIO KB16のキーマップを変更する

Windows10で[DOIO KB16](https://kibushop.com/products/kb16)のキーマップを変更しました。
VIAの設定サイトだけでは分からない箇所があったため、操作内容をまとめます。

## VIAへアクセス
https://usevia.app

### キーマップ設定方法
設定したいキーを選択し、SPECIAL > Any を選択。
![Animation (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818066/26eef4ac-06fb-5265-2a53-c5b666e5a823.gif)


#### マウス操作
| 操作 | 設定値 |
|:-:|:-:|
| 左クリック | KC_MS_BTN1 |
| 右クリック | KC_MS_BTN2 |
| 中央クリック | KC_MS_BTN3 |
| 進む | KC_MS_BTN4 |
| 戻る | KC_MS_BTN5 |


#### ショートカットキー
| 操作 | 設定値 |
|:-:|:-:|
| Ctrl + キー  | C(KC_o) |
| Alt + キー  | A(KC_o)  |
| Shift + キー  | S(KC_o)  |
| Win + キー  | G(KC_o)  |
| Ctrl + Alt + キー  | LCA(KC_o)  |
| Ctrl + Shift + キー  | RCS(KC_o)  |
| Alt + Shift + キー  | LSA(KC_o)  |
| Win + Shift + キー  | LSG(KC_o)  |
| Ctrl + Shift + Alt + キー  | MEH(KC_o)  |
| Ctrl + Shift + Win + キー  | HYPR(KC_o)  |

#### その他
| 操作 | 設定値 |
|:-:|:-:|
| キー未割当  | KC_NO  |
| LAYER0へ切り替え  | TO(0) |
| LAYER1へ切り替え  | TO(1) |

他設定値は下記サイトを参照。

https://docs.qmk.fm/keycodes

### キーマップ設定例

- Chromeの「画像をコピー」を選択（右クリック + Y）
  - `KC_MS_BTN2`
  - `KC_Y`
- 次のWindowへ移動（Alt + Tab）
  - `A(KC_TAB)`
- Eagleのショートカットキー（Ctrl + Shift + Alt + T）
  - `MEH(KC_T)`
- Eagleのショートカットキー（Ctrl + Shift + O）
  - `RCS(KC_O)`
- タブを閉じる（Ctrl + W）
  - `C(KC_W)`


## 参考サイト
https://salicylic-acid3.hatenablog.com/entry/via-manual

https://syon.github.io/refills/rid/1471100/

https://nogameb.com/archives/post-92583.html

https://note.com/tsuwami/n/n54933a87ee0c

https://note.com/tsuwami/n/ne208ee4a7e03

https://green-keys.info/doio-kb16-review/

https://visionarybucks.com/tipsofviasettings/

https://zenn.dev/kickbase/articles/22f62ffa1e438b

http://mihihi.blog.fc2.com/blog-entry-263.html
シェルスクリプトで使えるgotoコマンドを作ってみた

## はじめに

かつてシェルスクリプトではフロー制御に `goto` コマンドが使われていました。Bourne シェルが誕生するよりも前の Thmopson シェルの時代の話です。`goto` コマンドはシェルビルトインコマンドではなく外部コマンドとして C 言語（初期はアセンブリ言語）で実装されていました。`goto` コマンドを外部コマンドとして実装できるということは、シェルを改造したりしなくても、今のシェルで使える `goto` コマンドが作れるはずですよね？ ということで作ってみました。時代に逆行したシェルスクリプトを書きたい人にどうぞ（念の為ですがジョークです。これは研究用であり実用目的ではありません。実用目的には必ず `for` や `while` などのシェル組み込みのフロー制御命令を使用してください）。

## goto コマンドの実装

```c:goto.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_LINE_LENGTH 256

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <label>\n", argv[0]);
        return 1;
    }

    const char *label = argv[1];
    char line[MAX_LINE_LENGTH];
    char target[MAX_LINE_LENGTH + 3];  // ": " + label + "\n" のため

    // ": <label>\n" という形式のターゲットラベルを作成
    snprintf(target, sizeof(target), ": %s\n", label);

    // ファイルポインタを最初に移動（シーク）
    if (fseek(stdin, 0, SEEK_SET) != 0) {
        perror("Error seeking to the beginning of stdin");
        return 1;
    }

    // 標準入力から一行ずつ読み込み、ラベルが見つかるまで繰り返す
    while (fgets(line, sizeof(line), stdin)) {
        if (strcmp(line, target) == 0) {
            // ラベルが見つかったら終了
            return 0;
        }
    }

    // ラベルが見つからなかった場合
    fprintf(stderr, "Label '%s' not found.\n", label);
    return 1;
}
```

## シェルスクリプト側

```sh:test.sh
# カレントディレクトリにある goto コマンドを使えるようにするため
PATH=$PATH:.

i=1
: start

if [ "$i" -gt 10 ]; then
  goto end
fi

echo "$i"
i=$((i + 1))

goto start

: end
echo end
```

## 実行結果

動作するシェルは bash、ksh、mksh、yash です。dash、zsh では動作しませんでした。推測ですが動かないシェルでは最適化のために、シェルスクリプトを 1 行ずつ読み込むのではなく、ある程度まとめて読み込んでいたりするのでしょう。

```console
$ bash < test.sh
1
2
3
4
5
6
7
8
9
10
end
```

## 解説

`goto` コマンドの実装は、単純にラベルの形式 `: <ラベル>` の行が見つかるまで一行ずつ読み取ってファイルポインタを移動しているだけです。`:` は Thompson シェルではコメントを記述するためのもので、`goto` コマンドはコメントをラベルとして扱っていました。現在のシェルの `:` コマンド（ヌルコマンド）が何もしないコマンドなのは Thompson シェルでコメントだったときの名残です。

ここでのポイントは `bash` コマンドに対して**標準入力からシェルスクリプトをデータファイルとして入力**していることです。シバンで実行することはできません。シェルスクリプトの入力に標準入力を使うことで、シェルと `goto` コマンドで同一のシェルスクリプトファイルのファイルディスクリプタを共有することができます。シェルがコードを 1 行ずつ実行し、`goto` コマンドで次に実行するコードの位置（ファイルポインタ）を移動しているわけです。

この手法の欠点は、標準入力をシェルスクリプトファイルの読み込みに使ってしまっているために、シェルスクリプトの中から別のファイルをデータとして標準入力から読み込むことができないことです。Thompson シェル時代のシェルスクリプト（当時はコマンドファイルなどと呼ばれていました）は、プログラムではなくコマンド実行の履歴を記録したデータファイルでした。後の Bourne シェルではシェルスクリプトはプログラムとして、標準入力ではなくシェルの引数で渡せるように改良されました。

## さいごに

「`goto` コマンドを作ってみた」と言いましたが、実は嘘です。全部 ChatGPT さんに作ってもらいました。C 言語のソースコードは一切手を加えていません。いやー、楽ですね。

シェルの歴史に興味がある人へ。実は Thompson シェルを現在の OS に移植した人がいて、こんな物を作らなくても良かったりします。

https://github.com/eunuchs/tsh

Thompson シェルでは `goto` だけではなく `if` も外部コマンドです。またグロブパターンを展開する処理もシェルから外部コマンドを呼び出して実行しています（どこかでメモリが少なかったから外部コマンドに分離させたとかいうのを見た気がします）。ちなみに `cd` コマンド（当時は `chdir` コマンド）はさすがに外部コマンドではありません。[Thompson シェルのマニュアルなどはこちら](https://www.in-ulm.de/~mascheck/bourne/#origins)へどうぞ。
Chakra UI の Reset CSS の影響範囲を限定する

## Chakra UI の Reset CSS

[Chakra UI](https://v2.chakra-ui.com/) を使う際、プロジェクト全体を以下のように `ChakraProvider` で囲む必要があります。

```jsx
import { ChakraProvider } from '@chakra-ui/react';
import MyChakraApp from './MyChakraApp';

export default function ProjectRoot() {
  return (
    <ChakraProvider>
      <NyChakraApp />
    </ChakraProvider>
  );
}
```

この `ChakraProvier` は、ブラウザのデフォルトCSSを打ち消す機能（Reset CSS）を持ちます。Chakra UI のセットアップの一環として Reset CSS を適用することで、どの環境でも同じUIを提供する目的と思われます。Chakra UI を使う場合、ページ全体にChakra UIを適用する場面が多いと思われるため、基本的にはこの Reset CSS はそのままで問題ないでしょう。

ただ、ページ内で部分的に Chakra UI を適用したいシチュエーションにおいて、Reset CSS が画面全体に効いてしまうと嬉しくありません。デフォルトでは ChakraProvider の中のみならず、ページ全体に Reset CSS が効きます。そのような場面の対処法を記載します。


## 画面の一部にChakra UIを適用する

`ChakraProvier` のプロパティに `resetScope` というプロパティがあるのでこれを利用します。これは Reset CSS の範囲を CSS にて指定するというやりたいことそのままのプロパティです。


```jsx
import { ChakraProvider } from '@chakra-ui/react';
import MyChakraApp from './MyChakraApp';
import MyApp from './MyApp';

export default function ProjectRoot() {
  return (
    <>
      <ChakraProvider resetScope=":where(#my-css-reset-scope)">
        <div id="my-css-reset-scope">
          <MyChakraApp />
        </div>
      </ChakraProvider>/
      <MyApp />
    </>
  );
}
```

これで Reset CSS のスコープが `id="my-css-reset-scope"` を持つタグ内に限定されるため、`<MyApp />` は Reset CSS の影響を受けません。疑似クラス `:where()` を当てないと Reset CSS の優先順位が正しく適用されず、うまくいかない点に注意してください。


## ChakraProvier以下の一部をReset CSSの影響下から除外する

基本的にはChakra UIを使いたいけれど、一部パーツには Chakra UI を使いたくない、という場合です。筆者が試した限りでは、上記方法ではこのような場合には対応できないようです。

この場合の解決策の1つとして、[Shadow DOM](https://developer.mozilla.org/ja/docs/Web/API/Web_components/Using_shadow_DOM) を使って一部コンポーネントをReset CSSの影響から外す方法があります。[React Shadow](https://github.com/Wildhoney/ReactShadow?tab=readme-ov-file) ライブラリを用いることで、特定の領域に対して簡単にShadow DOMを適用することができます。

```jsx
import { ChakraProvider } from '@chakra-ui/react';
import ReactShadowRoot from "react-shadow";
import MyChakraApp from './MyChakraApp';
import SomeChakraApp from './SomeChakraApp'
import NonChakraApp from './NonChakraApp'

export default function ProjectRoot() {
  return (
    <>
      <ChakraProvider>
        <MyChakraApp />
      </ChakraProvider>
    </>
  );
}

function MyChakraApp() {
  return (
    <>
      <SomeChakraApp />
      <ReactShadowRoot.div>
        <NonChakraApp />
      </ReactShadowRoot.div>
    </>
  );
}
```

上記の例で言うと `<NonChakraApp />` コンポーネント以下は Reset CSS の影響を受けなくなるため、この下で独自のスタイリングを行うことが可能です。
ゲーム画面を画像分析してみた

### 背景
プレイ中のゲーム画面を画像分析させたりできないかなぁと思っていた所、思っていたよりかなり簡単に実装できたので記事にしました。

### 使用技術
- Python
- Pillow（画像を扱うためのライブラリ）
- OpenCV（画像解析用ライブラリ）

### 実際の例
今回は例として、テトリスを画像分析してみることにします。

    import cv2
    import numpy as np
    from PIL import Image, ImageGrab
    import time

    # 1.テトリスブロックのテンプレート画像ファイルのパス
    block_templates = ['block_I.png', 'block_J.png', 'block_L.png', 'block_O.png', 'block_S.png', 'block_T.png', 'block_Z.png']

    def capture_screen():
        """スクリーンショットを取得してOpenCV形式に変換"""
        screenshot = ImageGrab.grab()
        image_np = np.array(screenshot)
        return cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)

    def detect_blocks(frame, templates):
        """画像内のテトリスブロックを検出"""
        gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        detected_blocks = []

        for template_path in templates:
            template = cv2.imread(template_path, cv2.IMREAD_GRAYSCALE)
            w, h = template.shape[::-1]

            result = cv2.matchTemplate(gray_frame, template, cv2.TM_CCOEFF_NORMED)
            _, max_val, _, max_loc = cv2.minMaxLoc(result)

            if max_val > 0.8:  # 一致度が高い場合
                detected_blocks.append((template_path, max_loc, (w, h)))

        return detected_blocks

    while True:
        # 2.ゲーム画面をキャプチャ
        frame = capture_screen()

        # 3.ブロックを検出
        blocks = detect_blocks(frame, block_templates)
        
        # 4.検出結果を表示
        for block in blocks:
            template_path, (x, y), (w, h) = block
            print(f"Detected {template_path} at position ({x}, {y})")

            # 5.検出したブロックを矩形で囲む
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

        # 6.キャプチャした画像を表示（デバッグ用）
        cv2.imshow('Detected Blocks', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

        time.sleep(5)  # 5秒ごとに実行

    cv2.destroyAllWindows()


#### コードの説明
##### 1. テトリスブロックのテンプレート画像ファイルのパス
テトリスの各ブロックの画像を用意します。
画像例：
![block_O.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2221375/c8b147db-f8b1-7e71-5149-c3fd000fbc4d.png)

##### 2. ゲーム画面をキャプチャ
今開いているPCの画面全体のスクリーンショットを取ります。

##### 3. ブロックを検出
テンプレートマッチングにかけ、各ブロックに一致する箇所の一覧を取得します。

##### 4. 検出結果を表示
ブロックが存在した座標をシェルに出力します。

##### 5. 検出したブロックを矩形で囲む
ブロックを色つきの長方形の枠で囲い視覚的に分かるようにします。

##### 6. キャプチャした画像を表示（デバッグ用）
最後に画面上に、画像分析の結果を出力します。
私の環境では、いい感じに表示できなかったので調整は必要です。


### 感想
難しい部分をライブラリがやってくれているおかげで、かなりシンプルなコードで実現することができました。
応用すれば、結構できそうなことがありそうだなと思いました。
SharePoint のフォントの種類が何か知りたい時にどこで見るの？って話

気ままに勉強会のアフタートークで SharePoint のリスト部分だけフォントが変わってて、ちょっと違和感があるよねって話をしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/740543a3-3d26-d79c-66ea-754d9e1906a9.png)


その時に MVP 2人がかりで開発者ツールの見方を教えてもらうという贅沢なことをしてしまったので、メモしておきます。
※ [やまさん](https://twitter.com/yamad365) ・[たなさん](https://twitter.com/dreams_panda) 、ありがとうございました！

1. お手持ちの SharePoint サイトを開きます

2. ブラウザの設定 > その他のツール > 開発者ツール をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/50c8da8f-5301-986a-c2ab-23c8eba847bc.png)

3. 右側に「開発者ツール」が開きます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/c223372b-1e31-c27a-c838-11c3f53a4280.png)

4. 「要素」のタブを選択します

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/7a853ef8-a2ca-ad20-999c-b0d102b83c25.png)

5. 開発者ツール左端の「ページ上の検査対象となる要素を選択」をクリックします

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/14ab2228-5dc5-866a-ed5c-6994c111c881.png)

6. フォントの種類が知りたい部分にカーソルを当てます

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/38c12bde-376b-4c6d-c49e-a21c5ceff0de.png)

7. 吹き出しのところに Font が出てきます

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/4a929e6b-eed9-eb8d-0f75-a73b43db3503.png)

# もっと詳しく知りたい時は？
吹き出しだと「……」で省略されているところまで見たい時の方法です。

1. 開発者ツール左端の「ページ上の検査対象となる要素を選択」をクリックします

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/14ab2228-5dc5-866a-ed5c-6994c111c881.png)

2. フォントの種類が知りたい部分をクリックします

3. フィルターに「font」と入力します

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/b020a034-1b4f-071d-2a61-36e2642119c3.png)

4. font-family の部分がクリックした要素で使用されているフォントの種類です

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/fff46d3c-c35f-3bc8-8f21-c5a62da6701e.png)

    吹き出しでは省略されてしまっている部分もここで見ることができます
    font-family は、ウェブページでフォントスタイルを指定するために使用されます
    今回の場合だと "Yu Gothic UI" が第一優先のフォントで、もし"Yu Gothic UI" がない場合は "Meiryo UI" でそれもなければ、さらに右隣のフォント……というように順番に回していくようです

# 終わりに
SharePoint のフォントの確認方法と題しましたが、実際は開発者ツールの使い方ですｗ
多分、プロのエンジニアの方々には常識的なことでしょうが、私のようにローコードから IT に入ると抜け落ちる部分だと思いますし、普段使わないとすぐに忘れてしまうので記録に残しておきます(*‘∀‘)
Go | module declares its path as: <package-name> but was required as: <full-path>

自分でCLIツールを作成してリリースしたが利用側でパッケージを取得しようとしたらエラーが発生したのでその時の対応のメモ。

## 結論

まずは結論から。

提供しているmodule名を変更した上で再リリース（自分の場合はタグの変更で発火するGHAで再リリース）

```diff_go:go.mod
- module gen-slice-accessor
+ module github.com/snamiki1212/gen-slice-accessor
```

- [fix: update importpath · snamiki1212/go-gen-slice-accessors@e269c8f · GitHub](https://github.com/snamiki1212/go-gen-slice-accessors/commit/e269c8fcb8babac205f8d9f3880816f6aa02d3ee)

:::note warn
リポジトリ・モジュール名を変えたので読み替えてください
```diff
-gen-slice-accessor
+go-gen-slice-accessors
```
:::

## 発生していたエラー

- パッケージ/リポジトリ名: `gen-slice-accessor`
- GitHub アカウント名: `snamiki1212`

```zsh
$ go install github.com/snamiki1212/gen-slice-accessor@latest
go: github.com/snamiki1212/gen-slice-accessor@latest: version constraints conflict:
	github.com/snamiki1212/gen-slice-accessor@v0.0.1: parsing go.mod:
	module declares its path as: gen-slice-accessor
	        but was required as: github.com/snamiki1212/gen-slice-accessor
```

## 結果

```zsh
$ go install github.com/snamiki1212/gen-slice-accessor@latest
go: downloading github.com/snamiki1212/gen-slice-accessor v0.0.2
```

これで取得できるようになった

## Appendix1. go:generate

コード生成を行うためのCLIを作成していたので、go:generate 側でのコマンドとしては下記のようにすればinstallを明示する必要がない

```go:User.go
//go:generate go run -mod=mod github.com/snamiki1212/gen-slice-accessor@v0 --flag1=hoge
```
mysql_native_passwordのMySQLが欲しいときのdocker-compose

MySQL8.4からmysql_native_passwordがデフォルト無効になったらしい。
以下の小細工でmysql_native_password有効なMySQLが立ち上がる。

```
docker-compose.yml
docker-entrypoint-initdb.d/
  001_setup.sql
```

```docker-compose.yml
services:
  mysql:
    image: mysql:8.4.2
    container_name: mysql
    command: --mysql-native-password=ON
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: testdb
    volumes:
      - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
```

```sql:docker-entrypoint-initdb.d/001_setup.sql
ALTER USER `root`@`%` IDENTIFIED WITH mysql_native_password BY 'password';
ALTER USER root@localhost IDENTIFIED WITH mysql_native_password BY 'password';
```

```sh
# docker compose up -d
// ここでdocker-entrypoint-initdb.d/が実行される時間がしばらくあるので待つ20秒くらい
# docker compose exec mysql mysql -ppassword -e "select user, host, plugin from mysql.user;"
+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| root             | %         | mysql_native_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session    | localhost | caching_sha2_password |
| mysql.sys        | localhost | caching_sha2_password |
| root             | localhost | mysql_native_password |
+------------------+-----------+-----------------------+
```
Kubernetesノードのコントロールプレーンを変更しようとしたらcrictlからpodを削除できなくて困った

一度構築したKubernetesクラスタをリセットして再構築したくなることありませんか？
Kubernetesのトラブルを真面目に解決しようとすると数日吹き飛ぶことはママあると思っています。
そういう時は、「バルス」、いわゆる破滅の呪文でラピュタもといKubernetesクラスタを吹き飛ばして、再構築してしまうほうが早いです。
幸い、私はKubernetesの構築をAnsibleで行っているので、再構築は待っているだけでできます。

しかしながら、たまに破滅の呪文が正常に動作しないことがあります。
具体的な手順は以下の通りです

- kubeadmをリセットする
- systemdのデーモンをリロードする
- kubeletを停止する
- `crictl rmp -af`で全てのポッドを削除する
- kubeletをスタートする

本来、`crictl rmp -af`はエラーを無視して、podを削除するコマンドですが、現実にはpodの削除に失敗する場合があります。

そういう時は、以下のコマンドが有効です。

```bash
ip route flush proto bird
ip link list | grep cali | awk '{print $2}' | cut -c 1-15 | xargs -I {} ip link delete {}
modprobe -r ipip
```

本当は参考にしたissueがあったのですが、見失ってしまいました。
この後は`crictl rmp -af`から再度実行すれば先ほどは削除できなかったポッドを全て削除することができます。
staticについての簡易まとめ（Java初心者向け）

## staticをざっくり一言でいうと
変数やメソッドを共用できる魔法の修飾子！
※通常はインスタンス化が必要。

:::note info
10/9追記
メソッドやフィールドの呼称についてコメントで教えてくださいました！
* staticで修飾なし　→　インスタンス〇〇
※staticで修飾されていないものはインスタンス化しないと利用できないからですね。
 
* staticで修飾あり　→　クラス〇〇

詳細についてはコメントをご確認ください！
表付きで教えてくださってますので！
:::

## staticにできるもの
* 変数
* メソッド

変数やメソッドをクラス間で共用や上書きができると便利なときもありますよね。
しかし、不意な変更をしてしまう可能性もあるので注意しましょう。

## ざっくり説明
まず、通常の変数やメソッドの場合、クラス間で共用するには
1. クラス内で変数やメソッドを定義。もしくはメソッド内で変数を定義。
2. 使用したい変数やメソッドが記載してあるクラスのインスタンスを生成
3. インスタンス経由て変数やメソッドにアクセスする

このような手順となります。
しかし、staticの場合はこれが簡略化されます。
1. クラス内で変数やメソッドを**static**を付けて定義。もしくは、メソッド内で変数を**static**を付けて定義。
2. そのまま変数やメソッドを利用できる！

## 説明
なぜインスタンスを作らなくても使用できるのかについて見ていきましょう。
### プログラムの動き
Aクラス（メイン）とBクラス、Cクラスを使用するプログラムを例に考えます。
それぞれのクラスの記載内容は以下となります。
* **Aクラス**
    * メインメソッド
    * Bクラスのインスタンス生成
    * Bクラスの変数とメソッドを使用（このとき、上で作ったBクラスのインスタンスを使用している）
    * Cクラスのstatic変数とstaticメソッドを使用
* **Bクラス**
    * 変数とメソッドの定義
* **Cクラス**
    * static変数とstaticメソッドの定義
    
このプログラムがコンパイル、実行されたときの動きは下記のようになります。
1. **各クラスが読み込まれる**
2. Aクラス実行
3. Aクラスの記載順に、まずはBクラスのインスタンスが生成される
4. Aクラスに記載されているBクラスの変数やメソッドから、処理がBクラスに移る
5. Bクラスの該当箇所の内容が上から順に読み込まれ、実行される。処理が終わったら、Aクラスに戻る
6. Aクラスに記載されているCクラスの変数やメソッドから、処理がCクラスに移る
7. Cクラスの該当箇所の内容が上から順に読み込まれ、実行される。処理が終わったら、Aクラスに戻る
8. 全ての読み込みが完了し、プログラムが終了する


注目していただきたいのは、**Bクラスの変数やメソッドと、Cクラスのstaticな変数やメソッドは、メモリ空間上の別の場所に配置されているということです。
手順1「各クラスが読み込まれる」ときに、staticな変数やメソッドは専用のstatic領域に配置されます。
一方、通常の変数やメソッドは、メモリ空間の各インスタンス内に個別に配置されます。**
そのため、通常の変数やメソッドは
* インスタンスを生成し、生成したインスタンス経由で使用する
* 各インスタンス内で個別に作られるため、同名であっても異なる値を持つ

というわけなんですね。

そしてstaticな変数やメソッドの場合は
* メモリ空間上の専用領域に配置される
* インスタンス内にあるわけではないので、インスタンスを生成する必要がない
* 専用空間に配置されるので、同名のstaticなものを複数定義できない
* 参照先が一つなので、どのクラスからアクセスしても同一の値を返す

となるわけです。

## staticの真意
冒頭でお伝えした、『staticとは変数やメソッドを共用できる魔法の修飾子！』というのは半分当たっていて、半分外れています。
プログラムを動かしたときに、複数のクラスから呼び出されるstatic変数やstaticメソッドが、呼び出す度に値や実行内容が変わってしまっては大変ですよね。

**実は、static（意味：静的な、不活の、動きのない）の真意は、『参照先が一つなので、どのクラスからアクセスしても同一の値を返す　=　変わらないものを定義する時に利用する』です。**

例えばファイルパスや変更予定のない変数（定数）、内容が変わってしまっては困るメソッドなどへの使用が主となります。

## staticの注意点
staticメソッドから、通常の変数やメソッドへアクセスすることはできません！
staticからはstaticなものへのみ、アクセスできます。

## まとめ
staticとは不変に保ちたい（クラス）変数や（クラス）メソッドにつける修飾子であり、staticな（クラス）変数や（クラス）メソッドは、インスタンスを生成しなくても使用することができます。

## 後書き
私自身、Javaを勉強している途中ですので、記事内の表現について誤った部分のある可能性があります。
概略は間違っていないと思いますので、初心者の方の理解促進の一助となっていれば幸いです。
また、冒頭と終わりで真逆に近いような内容を伝えていることについては、ヒングロマクソン族でいうマダオみたいな感じで受け取っていただければと……。
【シェルスクリプト】全ての引数を1つの変数で扱う方法

`$*` や `$@` はシェルスクリプトに渡されたすべての引数を表します。

## `$*` と `$@` の使い方

- **`$*`**: すべての引数を1つの単一の文字列として扱います。引数はスペースで区切られます。
- **`$@`**: すべての引数を個別の引数として扱います。引数はそれぞれ独立しており、特にダブルクォートで囲むと、空白を含む引数も正しく処理されます。

## 具体例と `$*` と `$@` の違い

```bash:example.sh
#!/bin/bash

echo "\$* の出力: $*"
echo "\$@ の出力: $@"
```

引数を渡して上記のスクリプトを実行します。

```bash
$ bash ./example.sh "引数1" "引数 2" "引数3"
$* の出力: 引数1 引数 2 引数3
$@ の出力: 引数1 引数 2 引数3
```

結果は同じように見えますが、引数をループ処理すると違いがわかります。

```bash:example.sh
#!/bin/bash

echo "Using \$*:"
for arg in $*; do
    echo "$arg"
done

echo "Using \$@:"
for arg in "$@"; do
    echo "$arg"
done
```

このスクリプトを実行すると、次のような出力が得られます。

```terminal
$ bash ./example.sh "引数1" "引数 2" "引数3"
Using $*:
引数1
引数
2
引数3
Using $@:
引数1
引数 2
引数3

```

この例では、`$*` を使用した場合、引数がスペースで分割されてしまい、`"引数 2"` が2つの引数として扱われてしまいます。一方、`$@` を使用した場合、引数は正しく処理され、空白を含む引数も1つの引数として扱われます。
【TypeScriptで学ぶアルゴリズム】深さ優先探索(DFS)

## 深さ優先探索
木構造のデータを調べていく際に左側（片方）のノードを進めるだけ巡回し、先端まで辿り着いたら親要素へ戻り右側の要素へ進んでいくといった処理を繰り返す探索方法です

## 深さ優先探索の実装例

### 1. グラフを表すデータの型定義
```dfs.ts
//グラフの隣接リストを表す型
type Graph = { [key: string]: string[] };

```

### 2. DFSの実装
```dfs.ts
function dfs(graph: Graph, start: string, visited: Set<string> = new Set()): void {
  //開始ノードを巡回済みとしてセットに追加
  visited.add(start);
  console.log(start); //巡回したノードを表示

  //隣接するすべてのノードに対して探索を実行
  for (const neighbor of graph[start]) {
    if (!visited.has(neighbor)) {
      dfs(graph, neighbor, visited); //再帰的にDFSを実行する
    }
  }
}
```

### グラフデータの定義
```dfs.ts
const graph: Graph = {
  'A': ['B', 'C'],
  'B': ['D', 'E'],
  'C': ['F'],
  'D': [],
  'E': ['F'],
  'F': []
};
```

### 実行！

```dfs.ts
//'A'ノードからDFSを開始します
dfs(graph, 'A');
```
出力結果
```
A
B
D
E
F
C
```
上記を見るとしっかり深さ優先探索されていることが分かります！
（ノードAからスタートし、B -> D -> E -> F -> Cという順序で巡回します）