OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】form_withとかlocal: trueとかdata: { turbo: false }を理解してなかったので色々調べた

## 自己紹介
はじめまして、はる（[@lemonade_37](https://twitter.com/lemonade_37)）と申します。
駆け出しエンジニアとして働き始めて約2ヶ月弱が経過しました🐣


## 概要
仕事中、form_with関係の実装で詰まり、自分の理解が浅かったツケが来たのを感じたので、調べてみました😇
お恥ずかしながら、スクール時代はRails5、今はRails7を触っており、Railsのバージョンごとでの違いがごちゃ混ぜになっていたこと、フォームのオプションやそもそもAjaxなどきちんと理解できていなかったので調べたことをまとめます。


:::note warn
間違っている箇所があるかもしれませんので、その際は是非教えて頂けると嬉しいです🙇
:::


## フォームの非同期送信に関するオプション
### Rails5以前
フォーム送信時、デフォルトではページ全体がリロードされます。非同期処理をするにはオプションを明示的に設定します。
- `remote: true`
Rails5以前でフォームのオプションで使われていました。Ajaxを用いて非同期にします。

### Rails5以降
`form_with`メソッドが導入され、フォーム送信時はデフォルトで非同期送信になりました。

- `local: true`
Rails5以降でフォームのオプションで使われていました。フォームが通常のHTTPリクエストとして送信され、ページ全体がリロードされます。
　　
- `local: false`
Rails5以降でフォームのオプションで使われていました。Ajaxを用いて非同期にします。

### Rails7以降
デフォルトでTurboが有効化され、リンクやフォームが基本的に非同期送信になりました。

- `data: { turbo: false }`
Rails7で導入されたTurbo Drive機能に関する設定です。フォームに限らず使用されます。
Rails7では、Turbo Driveはデフォルトで有効であり、リンクやフォームのクリックがページの全体リロード無しに非同期的に行われます。
この記載をすることで、Turbo Driveを無効にし、ページ全体をリロードする方式にします。


## Ajaxとはそもそも何か
定義を調べてみました。Wikipedia[1)](#引用記事)より、
> Ajax（エイジャックス、アジャックス）は、ウェブブラウザ内で非同期通信を行いながらインターフェイスの構築を行うプログラミング手法である。
XMLHttpRequest（HTTP通信を行うためのJavaScript組み込みクラス）による非同期通信を利用し、通信結果に応じてダイナミックHTML (DHTML) で動的にページの一部を書き換えるというアプローチを取る。
Ajax は『Asynchronous JavaScript And XML』の略

概念レベルでちゃんと理解できていない自分にとっては、こちらの記事が大変わかりやすかったです🙇‍♀️

https://wa3.i-3-i.info/word12672.html


## HTTPリクエストとはそもそも何か
フォームのオプションでは、`method: :post`などのようにリクエスト方法を指定することができます。
Railsのフォーム内で指定できるHTTPリクエストについて調べてみました。MDN[2)](#引用記事)より、

- `GET`
GET メソッドは、指定したリソースの表現をリクエストします。 GET を使用するリクエストは、データの取り込みに限ります。
- `POST`
POST は指定したリソースに実体を送信するために使用するメソッドであり、サーバー上の状態を変更したり、副作用が発生したりすることがよくあります。
- `PATCH`
PATCH メソッドは、リソースを部分的に変更するために使用します。
- `PUT`
PUT メソッドは対象リソースの現在の表現全体を、リクエストのペイロードで置き換えます。
- `DELETE`
DELETE メソッドは、指定したリソースを削除します。


## ここまで調べた上でformを再確認
ここまで調べた＋Railsガイドのフォームヘルパーのページを一通り読んでみた上で、
再度formを見てみます。
```erb
<%= form_with(model: @user, url: user_registration_path, method: :post, data: { turbo: false }) do |form| %>
```
この例の場合、
`User`のmodelオブジェクトに紐づけて、`user_registration_path`のurlに対して、`POST`methodでHTTPリクエストを送信する、フォームを生成しているということがわかりました。
またRails7において、このフォームでは`submit`時にページ全体をリロードするように`data: { turbo: false }`が設定されています。


## まとめ
今までオプションが多く、Railsのバージョンによっても書き方が変化したり、苦手意識を持ったままだったところを調べ、理解が少し深まりました。
また、ふんわりなんとなくAjaxって非同期通信のやつでしょ？という理解だったのが、実際の挙動について調べて勉強になりました。
まだまだRailsが深く理解できていない部分が多いため勉強していきます。

　
## 参考・引用記事
#### 引用記事
1）[Ajax - Wikipedia](https://ja.wikipedia.org/wiki/Ajax)
2）[HTTP リクエストメソッド - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods)
 
#### 参考記事
- [form_withがlocal: trueなのにviewが再描画されずにはまった件](https://qiita.com/NI57721/items/61b2c74dacab2840047f)
- [form_withのlocal: trueって必要なん？これ何なん？（Ruby on Rails）](https://qiita.com/kakudaisuke/items/e032c7705db00e8081dc)
- [初心者目線でAjaxの説明](https://qiita.com/hisamura333/items/e3ea6ae549eb09b7efb9)
- [Action View フォームヘルパー - Railsガイド](https://railsguides.jp/form_helpers.html)
- [HTTPメソッド9種類 | PATCHとPUTの違いも解説](https://omathin.com/http-method/)
mermaidで本の投稿サイトのddlを書いてみる

```mermaid
erDiagram

users {
  INT user_id PK
  VARCHAR(50) username
  VARCHAR(100) email "インデックス"
  VARCHAR(100) password
  TIMESTAMP created_at
}

books {
  INT book_id PK
  VARCHAR(100) title "インデックス"
  VARCHAR(100) author
  VARCHAR(20) isbn "インデックス"
  VARCHAR(100) publisher
  DATE publication_date
  TEXT description
  TIMESTAMP created_at
}

book_images {
  INT image_id PK
  INT book_id FK "インデックス"
  VARCHAR(200) image_url
  TIMESTAMP created_at
}

comments {
  INT comment_id PK
  INT user_id FK "インデックス"
  INT book_id FK "インデックス"
  TEXT content
  INT rating
  TIMESTAMP created_at
}

favorites {
  INT favorite_id PK
  INT user_id FK "インデックス"
  INT book_id FK "インデックス"
  TIMESTAMP created_at
}

users ||--o{ comments : "writes"
users ||--o{ favorites : "has"

books ||--o{ book_images : "has"
books ||--o{ comments : "has"
books ||--o{ favorites : "is marked as"
```
円周率を自力で求めようとした話

円周率って円の何かを求めるときに必ず使いますよね。
面積=半径×半径×円周率
円周=直径×円周率
でも円って数式で表すと
```math
x^2+y^2=1
∵sin^2θ+cos^2θ=1
```
となるので
```math
y=± \sqrt{1-x^2}
```
となりますので、例えばですが第一象限のデータ数を100個にして式に当てはめればいい感じに二次曲線になります。

# 面積から円周率を求める
これを使って積分すれば円の面積の4分の1が求まりますから、つまり第一象限の面積の4倍が円の面積と理論上近似できるという訳です。
実際にやってみましょう。
```Python3
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 1, 100)
y = np.sqrt(1-x**2)
plt.plot(x, y)
plt.plot(x, -y)
plt.plot(-x, y)
plt.plot(-x, -y)
plt.show()

total = 0
for i in range(len(x)-1):
    total = total + (x[i+1] - x[i]) * (y[i+1] + y[i]) / 2
print(total*4)
```
するとこのようなまず図形が出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/80b0b158-ac1c-d47c-9f35-9886f10b2729.png)

もう円と似たようなもんですよね。
しかし値はこうなりました。

```
3.1403991781146154
```
円周率は3.14159265(自分が覚えている範囲)なので最初3桁は合っていますが、意外と400セグメントだけでは足りないのかもしれませんね。

# ピタゴラスの定理を使うと
そもそも円周率って単位円の半円の円周って考えたらピタゴラスの定理を使って長さを計算した方が正確かもしれません。
```Python3
total = 0
for i in range(len(x)-1):
    total = total + np.sqrt((x[i+1] - x[i])**2 + (y[i+1] - y[i])**2)
print(total*2)
```
出力結果は3.141294099131327で4桁まで合っていました。

# まとめ
円周率はそもそも円周の長さなのでそりゃピタゴラスの定理使った方が良いよね。
日本語プログラミング言語Mind８で十進数計算（小数対応3）

## 割り算を作りました。
### 共通処理
```
Ｌ小数の商とは　（Ｌ小数、Ｌ小数、小数桁数、端数処理　→　Ｌ小数　）
　　　　小数Ａは　構造体情報
　　　　小数Ｂは　構造体情報
		精度は　　変数
		端数処理区分は　変数
　　　　整数Ａは　構造体　Ｌ小数型
　　　　整数Ｂは　構造体　Ｌ小数型		
		小数桁数Ａは　変数
		小数桁数Ｂは　変数
		小数桁数は　変数
		分子の桁上げは　変数		
		Ｗ商は　構造体　Ｌ小数型
		Ｗ余りは　構造体　Ｌ小数型
	小数Ａと　小数Ｂと　精度と　端数処理区分に　入れる
	精度が　０より　小さい
		ならば　０を　精度に　入れる
	つぎに
	小数Ａの　Ｌ小数桁数を　小数桁数Ａに　入れる
	小数Ｂの　Ｌ小数桁数を　小数桁数Ｂに　入れる
	ＭＡＸ（小数桁数Ａ,小数桁数Ｂ）を　小数桁数に　入れる
	小数桁数に　精度を　加え　分子の桁上げに　入れる
	小数Ａを　分子の桁上げ　Ｌ小数を指定桁桁上げし	整数Ａに　入れる
	小数Ｂを　小数桁数だけ　Ｌ小数を指定桁桁上げし	整数Ｂに　入れる
	整数Ａの　Ｌ符号に　１を　入れる
	整数Ｂの　Ｌ符号に　１を　入れる　
	整数Ａと　整数Ｂの　Ｌ正数の商と余りを　Ｗ商と　Ｗ余りに　入れる
	端数処理区分が　１と　等しい
		ならば　※　四捨五入
			Ｗ余りの　Ｌ整数の二倍と　整数Ｂを　Ｌ整数の大小比較し	０　以上
				ならば　Ｗ商と　Ｌ正整数に一加算結果を　Ｗ商に　入れる
				つぎに
		さもなければ
			端数処理区分が　２と　等しい
				ならば　※　切り上げ
					Ｗ余りと　　Ｌゼロを　Ｌ整数の大小比較し	１　以上
						ならば　Ｗ商と　Ｌ正整数に一加算結果を　Ｗ商に　入れる
						つぎに
				つぎに
		つぎに
	小数Ａの　Ｌ符号に　小数Ｂの　Ｌ符号を　掛けて　Ｗ商の　Ｌ符号に　入れる
	Ｗ商を　精度だけ　Ｌ小数を指定桁桁下げし	返す。
```
### 切り捨て、四捨五入、切り上げ
```
Ｌ桁未満切り捨てた商とは　（Ｌ小数、Ｌ小数、小数桁数　→　Ｌ小数　）
    ０の　Ｌ小数の商を　返す。

Ｌ桁未満四捨五入した商とは　（Ｌ小数、Ｌ小数、小数桁数　→　Ｌ小数　）
    １の　Ｌ小数の商を　返す。
	
Ｌ桁未満切り上げした商とは　（Ｌ小数、Ｌ小数、小数桁数　→　Ｌ小数　）
    ２の　Ｌ小数の商を　返す。
```
### テスト
```
Ｌ小数１は　構造体　Ｌ小数型。
Ｌ小数２は　構造体　Ｌ小数型。
Ｌ小数６は　構造体　Ｌ小数型。
メインは　　　　　　　　（ ・ －－＞ ・ ）
　　Ｗ文字列は　文字列実体
	「２つの小数の割り算をします。（空入力で終了）」と 表示し　改行し
	ここから
		「小数１＝」と　表示し
　　　　　　　　　文字列入力し　Ｗ文字列に　入れる
		Ｗ文字列が　空列？
			ならば　打ち切り
			つぎに
 		Ｗ文字列を　Ｌ小数変換し　Ｌ小数１に　入れる
		「小数２＝」と　表示し
			文字列入力し　Ｗ文字列に　入れる
		Ｗ文字列を　Ｌ小数変換し　Ｌ小数２に　入れる
		Ｌ小数１と　Ｌ小数２の　４桁　Ｌ桁未満切り捨てた商を　Ｌ小数６に　入れる
　　	「切り捨て商＝」と　表示し　Ｌ小数６を　Ｌ小数文字列変換し　表示し
		Ｌ小数１と　Ｌ小数２の　４桁　Ｌ桁未満四捨五入した商を　Ｌ小数６に　入れる
　　	「四捨五入商＝」と　表示し　Ｌ小数６を　Ｌ小数文字列変換し　表示し			
		Ｌ小数１と　Ｌ小数２の　４桁　Ｌ桁未満切り上げした商を　Ｌ小数６に　入れる
　　	「切り上げ商＝」と　表示し　Ｌ小数６を　Ｌ小数文字列変換し　表示し	
		　改行する		
	繰り返す。
 ```
 ### 実行結果
 ```
 c:\mind8\pmind\sample>lnum-sub03
２つの小数の割り算をします。（空入力で終了）
小数１＝100
小数２＝3
切り捨て商＝+33.3333四捨五入商＝+33.3333切り上げ商＝+33.3334
小数１＝200
小数２＝3
切り捨て商＝+66.6666四捨五入商＝+66.6667切り上げ商＝+66.6667
小数１＝123.456
小数２＝111.111
切り捨て商＝+1.1111四捨五入商＝+1.1111切り上げ商＝+1.1112
小数１＝8
小数２＝5
切り捨て商＝+1.6000四捨五入商＝+1.6000切り上げ商＝+1.6000
小数１＝8
小数２＝9
切り捨て商＝+0.8888四捨五入商＝+0.8889切り上げ商＝+0.8889
小数１＝123456789
小数２＝11111
切り捨て商＝+11111.2221四捨五入商＝+11111.2221切り上げ商＝+11111.2222
 ```
Gemini ProのAPIを無料で使い続けるための確認ポイント

## Gemini ProのAPIは 2024/5/2から課金開始

Gemini ProのAPIは無料で利用できます
ただし、以下に記載の通り、2024/5/2以降、課金が有効な Google Cloud Platform（GCP）のプロジェクトでAPIを利用する場合、従量課金の対象となるとのことです

> You can create a new project if you don't have one already or add API keys to an existing project. All projects are subject to the Google Cloud Platform Terms of Service, which you agree to when creating a new project, while use of the Gemini API and Google AI Studio is subject to the Gemini API Terms of Service.
Use your API keys securely. Do not share them or embed them in code the public can view.
Starting on May 2, 2024, if you use Gemini API from a project that has billing enabled, your use will be subject to pay-as-you-go pricing.
https://aistudio.google.com/app/apikey

## 無料で使い続けるための確認

課金が無効になっているGCPのプロジェクトでは無料で使い続けることができるので、課金が無効になっていることを確認しましょう

### 課金の有効/無効を確認

以下のURLを開き、Gemini API keyを利用しているプロジェクトを選択します

https://console.cloud.google.com/billing/linkedaccount

### 課金が無効になっている場合

![スクリーンショット 2024-04-25 22.44.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3741957/fb42b872-221d-3779-22f2-90c3521ec8b0.png)

### 課金が有効になっている場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3741957/29b60d23-fa78-b179-fce5-3322d37d25f9.png)

#### 課金を有効から無効に切り替える場合

以下のURLを開き、アクションから**課金を無効にする**をクリックします

https://console.cloud.google.com/billing/projects

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3741957/fe649752-318b-bff1-e41e-4bb482d2ddf7.png)

**課金を無効にする**をクリックすることで課金が無効になります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3741957/3bd1e460-4fff-8d85-34a2-2a0f0a810236.png)

**請求が無効です** と表示されれば変更完了です
![スクリーンショット 2024-04-25 23.26.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3741957/4b423908-2a57-e4d5-ce66-10bf278648e6.png)


## まとめ

|||
|:-:|:-:|
| 課金開始日 | 2024年5月2日 |
| 利用条件 | GCPのプロジェクトで課金が有効の場合、API使用料が発生する  |
| 無料での使用 | 課金が無効に設定されたプロジェクトでは引き続き無料で使用可能 |
| 課金状態の確認・変更 | [GCPの課金設定ページ](https://console.cloud.google.com/billing/linkedaccount)で課金の有効/無効を確認し、必要に応じて変更可能 |

2024年5月2日前に課金の有効/無効の状態を確認し、予期せぬ課金がないように注意しましょう
Github Actions（FirebaseExtended/action-hosting-deploy@v0）のwarning「Node.js 16 actions are deprecated.」を消したい

## はじめに

こんにちは！[@nyakako13](https://qiita.com/nyakako13 "Qiita ページ") です。

Github Actionsのworkflow実行時のwarningを消す時に調べたことをまとめます。

前回の続き？です。

https://qiita.com/nyakako13/items/0b1b216aaf8a6dc75f55

## やりたいこと
下のwarningを消したい。

![スクリーンショット 2024-04-24 10.42.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/d5b5b6d7-2629-1c60-bc42-e60febf1d8e0.png)



## 解決方法

.ymlファイルの該当アクションの参照方法をメジャーバージョンのタグ指定からコミットSHA指定に変更することで改善しました。

:::note info
アクションの@以降は指定方法がいくつかあります。
1. タグ名（メジャーバージョン、マイナーバージョン等）←これが多い
2. ブランチ名
3. コミットSHA

:::

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses

### 改善前
```yaml
- name: Deploy to Firebase Hosting
  uses: FirebaseExtended/action-hosting-deploy@v0
```
### 改善後
```yaml
- name: Deploy to Firebase Hosting
  uses: FirebaseExtended/action-hosting-deploy@vac8041b3b04337509168113bf98b95879df22322
```

## 原因
該当アクション（FirebaseExtended/action-hosting-deploy）内で使われているアクションのnodeバージョンが低いことがwarningの原因でした。

[対応済のコミット](https://github.com/FirebaseExtended/action-hosting-deploy/commit/ac8041b3b04337509168113bf98b95879df22322)はあるものの、まだ、リリースはされていませんでした。
また、このアクション（FirebaseExtended/action-hosting-deploy）のメジャーバージョンタグ(@v0)は最新のリリースにも対応していませんでした。

はじめはv0の指定でv0.7.1が自動的に適用されると思っていましたが（メジャーバージョンが一緒なので）、メジャーバージョン指定が最新のリリースと一致するかはアクションの提供側次第のため、今回は一致していません。

https://swfz.hatenablog.com/entry/2024/01/21/190358

また、最新のリリースがv0.7.1だったので`uses: FirebaseExtended/action-hosting-deploy@v0.7.1`で改善できると思っていましたが、対応済みのコミットはまだリリースタグがついてなかったのでコミットSHAで指定し、やっと改善できました。


v0とv0.7.1が違うコミットを指しています（2024/04/24現在）
![スクリーンショット 2024-04-24 11.35.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/a6db03f2-2455-e109-da9b-ec2e8f936c89.png)


https://github.com/FirebaseExtended/action-hosting-deploy/tags

よく使うcheckoutアクションでは最新のリリースとv4タグが同じコミットを指しています。（2024/04/24現在）

https://github.com/actions/checkout/tags

## 感想
ちょっとした疑問から調べていましたが、なんとなくしていたアクションのバージョン指定も奥が深く、githubのタグやリリースについても勉強になりました。

GithubActions公式のアクションではメジャーバージョンのタグ指定でも大きなトラブルはなさそうですが、サードパーティ製のアクションではマイナーバージョン指定やコミットSHA指定も視野にいれていこうと思います。

アクションのバージョン指定方法についてのメリット、デメリットはこちらの記事がとても参考になりました。

https://zenn.dev/snowcait/articles/53ec922a414dde

## おわりに
よかったら[X(@nyakako13)](https://twitter.com/nyakako13 "Xプロフィール")もフォローしてもらえると嬉しいです。

[Qiita100投稿](https://qiita.com/nyakako13/items/03ad61cfb82a1582b5d1)まで残り93！

未経験や浅経験、厳しいと言われている年代でエンジニアへの転職活動されている方、負けずにがんばりましょう！！

## 参考
https://zenn.dev/snowcait/articles/53ec922a414dde

https://swfz.hatenablog.com/entry/2024/01/21/190358
Figma tokens ＋ style dictionary でCSSを生成

# 背景
figmaで作成したtokenをGitHubにpushしてCSSファイルに書き出したい。
figma tokens → GitHub → style dictionary → CSSファイル

この記事の続き

https://qiita.com/_lemoo_/items/fc943fd4a2486f918b05

# なんでfigma tokensなのか
本当はfigamaの機能のvariablesでやりたかった。
→ variablesからtokenを書き出す方法が分からなかった。
（APIはエンタープライズプランから使える）
プラグインがあるかも。

# tokens.json をtransformする
GitHubにpushされたtoken.json

![スクリーンショット 2024-04-25 15.56.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689380/0316d9ea-4bf8-7732-b612-2a94547c6b71.png)



style dictionaryで使えるようにするためリポジトリにpushしたtokens.json をtransformする。
```terminal
// token-transformerをインストール
npm install -D token-transformer
```

package.jsonにスクリプトを追加する
（./data/tokens.json をtransformして output.jsonに書き出す）
```json
  "scripts": {
    "transform": "token-transformer ./data/tokens.json output.json"
  }
```

スクリプトを実行
```terminal
npm transform
```

transformされたoutput.json
![スクリーンショット 2024-04-25 16.00.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689380/e48051e9-5e9d-6209-db38-d23a8f67fd0a.png)

# style dictionaryでCSSを生成する

```terminal
// style-dictionaryをインストール
npm install -D style-dictionary
```

package.jsonにスクリプトを追加する
```json
  "scripts": {
    "start": "npm run transform && npm run build",
    "build": "style-dictionary build",
  }
```

config.jsonを作成する
```json
{
  "source": ["output.json"],
  "platforms": {
    "css": {
      "transformGroup": "css",
      "buildPath": "build/css/",
      "files": [{
        "destination": "variables.css",
        "format": "css/variables",
        "options": {
          "outputReferences": true
        }
      }]
    }
  }
}

```

スクリプトを実行
```terminal
npm build
```

CSSファイルが生成される

![スクリーンショット 2024-04-25 16.04.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689380/13ab5670-c0da-eb46-1662-256a10736866.png)

## 最後に
今度はnpmパッケージにする記事を書きたい。
パッケージのバージョン管理もいい感じにしたい。
超シンプル自分の予定を知らせるLINEBOT

# ただ自分の予定を身近な人に伝えるだけのBOT制作途中
### 自分の予定が時々変わることってよくあるりませんか？
私の場合は仕事の休みが不定期なのであるのと、同じ職場の人達の都合で勤務予定変更になることがあります。
全く無い月もありますが、月に２～３回変更がある時もあります。
私は近くに住む、家族に１ケ月の勤務表を前もって渡して私の休みの日を共有しています。時に家族たちは時に私の休みに合わせて予定を立てているときもある為、私の休みが変更になってガッカリさせたこともありました。
なのでそんな身近な人達に私のタイムリーな予定を確認してもらいたいと思って今回初めてLINEBOTに取り組んでみました。


#### とりあえずの完成品です






https://twitter.com/aTaKa2443/status/1783474907789332903








#### 使用ツールは

* LINE Developers
* SSSAPI
* MAKE
* Googleスプレッドシート

#### MAKEのシナリオは

![スクリーンショット 2024-04-25 18.29.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762532/a629c62b-47c3-e88e-e487-a67262e1b6e2.jpeg)


#### はて？なにから始めたらいいのか
といろいろ頭の中で考えてみてもそれをLINEBOT初心者の私には実現させられるノウハウが皆無、取り合えずはシンプルGoogleスプレッドシートを使ったシンプルなもで初めてみることにしました。
##### 作成したスプレッドシートをSSSAPIを使ってAPI化させました
:point_right:[リンクテキスト](https://sssapi.app/)


![Screenshot_20240425-203535~2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762532/e5b048a5-9128-ebd1-8aa2-08be38f512f7.png)

#### HTTPモジュール
当初Httpに貼るスプレッドシートのAPIをスプレッドシートのURLを貼ってしまって、未経験者アルアルをしておりました。私の様なミスをする人は居ないと思いますが、気を付けましょう。因みに私はもう二度と間違えないとおもいますが・・・:relaxed:

![スクリーンショット 2024-04-25 18.29.39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762532/b6fab8d6-0545-b1c8-6bd0-1fea4fc4037d.jpeg)

#### リプライメッセージの設定

今回は単純に一日だけの予定を返すことに成功しました。

![スクリーンショット 2024-04-25 18.30.37.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762532/22805a6d-0cb2-f6eb-3432-6dda2035f142.jpeg)


まだまだ完成には程遠いものですが、今後山ほどの修正と補足情報など加えた便利なものにしていきたいとおもいます。
これからはJavaScript勉強しよう　4回目


https://fadotech.com/quiz-javascript/

```html

<!DOCTYPE html>
<html lang="ja">

   <p>テストの点数を入力しましょう</p>
   <p>60点であれば合格です</p>
  <input type="text" id="score1">
  <input type="button" value="確認" id="btn">

  <p id="msg"></p>

<script>

function scorecheck(){

if (txtscore.value >= 101) {
  
msg.innerText = "入力に誤りがあります。"

} else if(txtscore.value >= 60) {

  msg.innerText = "合格です。"

} else {
  msg.innerText = "不合格です。"

}

}


txtscore = document.getElementById('score1');
btn1 = document.getElementById('btn');

btn1.addEventListener('click',scorecheck);

</script>
</html>



```
MacでPython環境を構築した話

環境構築しようと思って、ネットを探していたけれど、ほしい情報が全てまとまっているサイトがなかったためここに書きます

### MacにPython環境を構築する流れ
1. ターミナルを起動する
2. ターミナルでHomebrewをインストールする
3. Homebrew を用いて prenv をインストールする
4. pyenv を用いて Python をインストールする



### 1. ターミナルを起動する
「 Spotlight 」から「 Terminal 」と検索して起動する
「 Spotlight 」は、Command(⌘)＋Space で立ち上がるので、「 Terminal 」と入力して、「 Terminal 」を立ち上げる
![Screenshot 2024-04-25 at 20.59.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778441/28dbfd23-2d7a-0483-407c-4a4379836526.png)

### 2. Homebrewのインストール
以下の文章をコピペして実行する
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
````
以下のように「brew -v」と入力すると Homebrew のバージョンを確認可能
```
% brew -v
Homebrew 2.6.2
```
もしも以下のようになったら、、
これは正しくpathが通っていないことが原因になる（brewからコピペする）
```
% brew -v
zsh: command not found: brew
```
次のコードを実行する
ユーザー名を各自のものに変更し、echo・evalからコピペする
（1行目をコピペしてEnterを押したのちに、2行目をコピペ）
```
% echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/ユーザ名/.zprofile
% eval "$(/opt/homebrew/bin/brew shellenv)"
```

### 3. Hombrewを使ってPyenvをインストール
`pyenv`は以下のコードをターミナルで入力するとインストールできる
```
brew install pyenv
```
インストールできているのか確認する
```
pyenv -v
```
できたら次に、Pythonをインストールする
### 4. pyenv を用いて Python をインストールする
以下を実行する
```
pyenv install 3.12.2
```
執筆時点で最新のバージョンになるので、必要に応じて最新のものを使用してください
以下で、インストールできているか確認する
```
python --version
```
正しくインストールできていれば、以下が出てくる
```
% python --version
python 3.12.2
```
正しくいっていないといっていなければ、以下のような記載になる
```
% python --version
zsh: command not found: python
```
このときは、以下を実行する
```
echo "alias python=/usr/bin/python3" >> ~/.zshrc
```
改めてバージョンを確認すると上手く表示されると思う

あとはVScodeなどで実際にpythonを使ってみよう（後ほど記事にします）
arch bluetoothの接続がすぐに切れる

# 注意
archlinux 上で wayland を使用
bluetooth blueman を利用

# 問題点
bluetooth を接続された後に接続が切れる、または接続ができなくなる、という現象が起きた。
システムの再起動、ファイルの再インストール、コンフィグファイルの設定でも問題は解決せず。

# 原因
カーネル上でbluetoothのシステムがブロックされていることが原因であった。
システムの消費電力を抑えるために非アクティブな接続はブロックされるようになっているらしい。（初耳）

# 解決策
ブロックされているかの確認をする
```
rfkill list
```
もしBluetooth blocked: yes であったら下のコマンドを打つ
```
rfkill unblock all
```
これで再起動をすることで解決しました。
AZ-900合格体験記

## 結果
1000点満点中984点でした。
前日に、実際の試験画面である公式の試験サンドボックスで
試験の操作画面と操作方法を確認できたので、焦らず取り組むことができました。

## 参考資料
Examtopics

## 試験当日
テストセンターで受けてきました。
40分前に着いて受付(書類を読んでサインして免許証渡して写真撮って)して
ロッカーに移動して荷物入れてまた書類読んで試験会場へ案内されテスト受けました。
時間は45分で35問。残り30秒になるまで、テスト取り組みました。

## 感想
テストセンターは久々でしたが快適に試験を受けることができました。
ただ遠いので、次回は自宅で試験受けます。
あと、ケーススタディ問題はなく、問題はセクションごとに区切られていませんでした。
次は、AI-900取ります。おわり。
Pythonを使ってiphoneで撮影した写真から位置情報を抽出する

## 概要
iphoneで写真を撮影するにあたり位置情報を埋め込む設定を有効にしていると、撮影した写真に埋め込まれている[EXIF](https://ja.wikipedia.org/wiki/Exchangeable_image_file_format)と呼ばれるメタデータに位置情報が記憶されるようです。
そこで今回はiphoneで撮影した写真(HEIC形式)からpythonを用いて位置情報を抽出してみます。

## 使用環境

- OS：macOS Ventura 13.2.1
- Pythonバージョン：3.12.3

## 使用するライブラリ
### exifread
TIFF, JPEG, PNG, Webp, HEIC形式の画像ファイルからExifメタデータを抽出するPythonモジュールです。

https://pypi.org/project/ExifRead/



pipでインストールできます。
```terminal
$ pip install exifread
```
なお、exifreadのバージョン3.0.0を使用したところ、HEIC形式の画像ファイルからEXIFデータを読み込もうとする際に以下のエラーが発生したため、今回は無事動作が確認できたバージョン2.3.2を使用しました。

```terminal
Traceback (most recent call last):
  File "/Users/｛ユーザー名｝/python_project/gps_from_heic/.venv/lib/python3.12/site-packages/exifread/heic.py", line 171, in get_parser
    return defs[box.name]
           ~~~~^^^^^^^^^^
KeyError: 'hdlr'
```

## 写真のEXIFから緯度経度を抽出してみる
先日、華厳滝で撮影した写真を使用します。

```python
import exifread


def read_exif_from_image(image_path):
    """画像ファイルからEXIFデータを読み込む"""
    try:
        with open(image_path, "rb") as f:
            exif_data = exifread.process_file(f)
        return exif_data
    except FileNotFoundError:
        print(f"ファイルが見つかりません: {image_path}")
        return None
    except IOError:
        print(f"ファイルの読み込みに失敗しました: {image_path}")
        return None

        
def dms_to_decimal(dms):
    """度分秒（DMS）リストから10進数の座標に変換する関数"""
    degrees, minutes, seconds = dms
    return degrees + (minutes / 60) + (seconds / 3600)


def get_coordinates(exif_data):
    """EXIFタグから緯度と経度を抽出してタプルで返す"""
    try:
        pre_latitude = eval(exif_data["GPS GPSLatitude"].printable)
        pre_longitude = eval(exif_data["GPS GPSLongitude"].printable)
        latitude = dms_to_decimal(pre_latitude)
        longitude = dms_to_decimal(pre_longitude)
        return (latitude, longitude)
    except KeyError:
        print("必要なGPS情報が含まれていません。")
        return None


def main():
    image_path = "sample.HEIC"
    exif_data = read_exif_from_image(image_path)
    if exif_data:
        coordinates = get_coordinates(exif_data)
        if coordinates:
            print("緯度経度:", coordinates)
        else:
            print("GPS情報の取得に失敗しました。")
    else:
        print("EXIFデータの読み込みに失敗しました。")


if __name__ == "__main__":
    main()

```

出力
```
緯度経度: (36.737991666666666, 139.50366111111111)
```
![スクリーンショット 2024-04-25 21.51.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625929/0e58eb1c-7f43-c181-5b1a-aa86b551ae9e.png)
google mapで見たところ、正しく抽出できてそうです！

## おわりに
思いの外簡単に写真のメタデータを抽出できました。
最近SNSに位置情報のデータを含む写真をうっかりあげてしまって悪用された等の物騒な話も聞きますが、自分で撮影した写真の位置情報や撮影時間を使って旅の軌跡を振り返る等の楽しみ方もできそうですね。
Windowsエクスプローラー : 接頭文字が全角スペースのファイルを取扱う際の問題

# Windowsエクスプローラー : 接頭文字が全角スペースのファイルを取扱う際の問題

## [再現手順]
環境: Windows10 22H2

* 1.「全角スペース+Sample.txt」のファイルを作成します
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383255/e037ca30-6389-77fc-ee7b-03c8822ded75.png)



* 2.作成したファイルの名称を「Sample.txt」にリネームします(※できません）
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383255/c8460ce5-3ed9-9a3a-1aa7-02f7318db574.png)




* 3.そうすると「全角スペース+Sample.txt」はOS上で「Sample.txt」として扱われているのかと思いますが、コピー＆ペーストすると先頭の全角スペースが削除されたファイルが複製されます

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383255/4a2cb831-9d81-1431-46bb-df0b93450195.png)

* 4.コマンドでリネームする場合は成功します
```
ren "　sample.txt" "sample.txt"
```
エクスプローラーの問題のようです

-------------------------


調べてみると、Windows XPでは問題なかったようですが、
Windows Vista～Windows10はこの問題があるようです。

https://answers.microsoft.com/ja-jp/windows/forum/all/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D/dfb9773c-650b-4da7-9b8e-c577102eb045
Vite + Reactプロジェクトを途中からTypeScriptに変更する方法

どうもこんにちは、たくびー(@takubii)です。

今回はVite + Reactで作ったプロジェクトを途中からTypeScriptで書けるように設定する方法を共有します。

# パッケージのインストール

インストールするバッケージは以下の3つです。

- typescript
- @typescript-eslint/eslint-plugin
- @typescript-eslint/parser

```zsh:terminal
npm i --save-dev typescript　@typescript-eslint/eslint-plugin @typescript-eslint/parser
```

# Configファイルの追加、変更

```diff_typescript:vite.config.ts
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'

+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [react()],
+})
```

```diff_json:tsconfig.json
+{
+  "compilerOptions": {
+    "allowImportingTsExtensions": true,
+    "isolatedModules": true,
+    "jsx": "react-jsx",
+    "lib": [
+      "ES2020",
+      "DOM",
+      "DOM.Iterable"
+    ],
+    "module": "ESNext",
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "noEmit": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "resolveJsonModule": true,
+    "skipLibCheck": true,
+    /* Linting */
+    "strict": true,
+    "target": "ES2020",
+    "useDefineForClassFields": true
+  },
+  "include": [
+    "src"
+  ],
+  "references": [
+    {
+      "path": "./tsconfig.node.json"
+    }
+  ]
+}
```

```diff_json:tsconfig.node.json
+{
+  "compilerOptions": {
+    "allowSyntheticDefaultImports": true,
+    "composite": true,
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "skipLibCheck": true,
+    "strict": true
+  },
+  "include": [
+    "vite.config.ts"
+  ]
+}
```

# js(jsx)ファイルをts(tsx)ファイルに置き換えていく

```diff_html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
    ...
    <title>Vite + React</title>
  </head>
  <body>
    <div id="root"></div>
-    <script type="module" src="/src/main.jsx"></script>
+    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```

```diff_tsx:main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
-import App from './App.jsx'
+import App from './App.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
```

後はひたすらJS(JSX)ファイルをTS(TSX)ファイルに置き換えていってください。
ESLintを入れておくと拡張子を変換した時にファイル内でLintエラーを出してくれるので、そこを潰していくと効率よく置き換えができるのでインストール推奨です。

# 終わりに

私の場合、最初は実装の速さを重視しJavaScriptで実装を行なっていましたが、ある程度のコードベースになってくるとTypeScriptで型の厳密性や補完などの機能が欲しくなってきて思い切って全てのコードを置き換えました。

基本的にパッケージをインストールし、設定ファイルを追加するだけでTypeScriptを使えるようになるので最初はJS,TSどちらから始めても大丈夫だなと感じています。

それでは今回はこのあたりで締めたいと思います。
ここまで読んでいただきありがとうございます。
また機会があればお会いしましょう。
periodOverPeriodLastValue関数を使用した際のフィルターについて

## はじめに
本記事は、QuickSightでのperiodOverPeriodLastValue関数を利用した際に日付型でフィルターを掛けたとき一部数量が表示されない事象をテストデータを用いてQuickSight上で再現しつつ回避策を記載していきます。

## 事象
以下のようにperiodOverPeriodLastValue関数を使い、年月でフィルターを掛けた場合、開始月・年の前月・前年数量が表示されない事象が発生します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740281/77ca3536-25da-ded9-6ab8-50ccb2b87df6.png)

## 回避方法
上記事象を回避するには、クエリパイプラインのどこでフィルタが行われるかを操作する必要があります。そのため、フィルターにテーブル計算を使用することで、計算が行われた後にフィルタリングが行われます。以下より、詳細の手順を記載いたします。

①以下の計算式を使い、新規で計算フィールドを作成します。
minOver(min({日付型}), [{日付型}])

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740281/6f23debd-cf4b-9406-c65b-69a073cdccf9.png)

②作成した計算フィールドを使い、フィルターを掛けることで表示されなかった数量が表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740281/a17f903a-8d9b-2a5f-0387-abc81aac11e5.png)


## 参考文献
この記事は以下の情報を参考にして執筆しました。
How do I superimpose a period over period in a visual without having the period that I’m comparing it to in the visual?
(https://community.amazonquicksight.com/t/how-do-i-superimpose-a-period-over-period-in-a-visual-without-having-the-period-that-im-comparing-it-to-in-the-visual/2537)


## あとがき
本記事は、quicksightでレポートを作成していた際に上記事象が発生し、回避策に関する投稿があまりにも少なかったため執筆したのものとなります。
<br>
株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area
類似度の高いペアを高速に抽出する手法について (編集距離)


以下の標準化編集距離が一定以下のペアを全列挙する問題を考えます。

$X:$ 文字列の集合、 $\varepsilon$ : 類似度の閾値, $f_e: X\times X \to [0,1] $ : 標準化編集距離
$$
find \  \max_{S \subset X \times X} \ (y,z) \in S  \ {\rm s.t.} \ f_e(y,z) \le \varepsilon
$$

(標準化)編集距離についての記事は多数存在しますが、例えば [wikipedia](https://ja.wikipedia.org/wiki/レーベンシュタイン距離#:~:text=編集距離（へんしゅうきょ,回数として定義される%E3%80%82) を参照ください。

全ペア計算すれば求めることは可能ですが、より高速に(取りこぼしがなく)全列挙する方法を考えます。




$\forall x,y \in X$ に対し、$g(x,y) \le f_e(x,y)$ を満たすような $g: X\times X \to [0,1]$ を定義できた時

(1) $g(x,y)$ の値を先に計算

(2-a) $g(x,y) > \varepsilon$ を満たすとき、$f_e (x,y) > \varepsilon$が成立するため、 $f_e(x,y)$ の値を計算した上で $\varepsilon$ との大小比較を行う必要がない.

(2-b) $g(x,y)\le \varepsilon $ を満たすとき、$f_e (x,y)$ と $\varepsilon $ の大小関係は不明であるため、 $f_e(x,y)$ の値を計算し、 $\varepsilon$ との大小比較を行う

下記の２つの条件を共に満たす場合のみこのアプローチは有効となります。
- (2-b) の条件を満たすペアが (2-a) の条件を満たすペアより十分少ない
- $f_e$ に比べ $g$ が十分高速に計算可能


具体的な取り方の例)
$g : X\times X \to [0,1]$ を以下のように定義する.

$\forall x \in X$ , $C_x$ : $x$ で使われる文字列の集合 と定義する.

Ex) $x$ = "TOKYO" の時, $ C_x = \\{T, O, K, Y \\}$

$$
g(x,y) := \frac{\max \\{|C_x \setminus C_y|, |C_y \setminus C_x|\\}}{\max\\{|x|, |y| \\}}
$$
$\forall x,y \in X$ に対し、$g(x,y) \le f_e(x,y)$ を満たす.

(イメージ: 異なる文字は置換/削除の必要があるためコストを要する.)



この $g$ は　$f_e$ に比べ高速に計算可能である。
  - $f_e(x,y)$ の計算量: $O(|x| |y|)$ 
  - $g(x,y)$ の計算量:   $O(\max\\{|x|, |y| \\})$
    - cf) https://wiki.python.org/moin/TimeComplexity


----



例1) $x =$ "バナナ" , $y=$ "バハマ" の時

$f_e(x,y) = \frac{2}{3}$

$C_x = \\{バ, ナ \\}, C_y = \\{ バ、ハ、マ \\} $

$g(x,y) = \frac{2}{3}$

$g(x,y) \le f_e(x,y)$ を満たす.



例2) (等号成立しない例) $x =$ "トウキョウ" , $y=$ "キョウト" の時

$f_e(x,y) = \frac{3}{5}$

$C_x = \\{ト, ウ, キ, ョ \\}, C_y = \\{ ト, ウ, キ, ョ \\} $

$g(x,y) = 0$

$g(x,y) \le f_e(x,y)$ を満たす.



上記の方法が妥当であること(取りこぼしがないこと)は下記の補題により保証されます。

> $X: set, f_e : 標準化編集距離$,  $g(x,y) := \frac{\max \\{|C_x \setminus C_y|, |C_y \setminus C_x|\\}}{\max\\{|x|, |y| \\}}$ に対し、$\forall x, y \in X, g(x,y) \le f_e(x,y)$ が成立する.

(証明)

文字列の結合を＊で表現する。

$T$: 文字の集合を受け取り、要素をUnicodeの若い順に１文字ずつ並べた文字列を返す写像 とする. (Unicode順に特に意味はないです)

Ex) $C = \\{y,s,d\\}$ の時, $T(C) = $ "dsy"

$x,y$ に含まれる共通の文字を並べた文字列を $z$ とおく. 

$x,y$から $z$ に含まれる文字を抜いた文字列を $\bar{x}, \bar{y}$ とおく.


```math
\begin{align}
g(x,y)  &= \frac{1}{\max\{|x|, |y| \}} \max\{|C_x\setminus C_y|, |C_y\setminus C_x| \}
 \\ 
 &\le f_e ( T(C_x\setminus C_y), T(C_y\setminus C_x)) \\
 &= f_e(z * T(C_x\setminus C_y), z*T(C_y\setminus C_x)) \\
 &\le f_e(z*\bar{x}, z*\bar{y}) \\
 &\le  f_e(x,y)
\end{align}

```


この例のように適当な関数の値が一定以上(以下)のペアを高速に抽出したい場合はそれを下から抑えるor上から抑える関数を探してみてください。


謝辞: 議論に参加していただいた研究室の皆様、感謝申し上げます。
ED法を説明図からpytorchで実装


https://github.com/Shumpei-Tanaka/Error-Diffusion-Model

## 話題のED法、誤差拡散法による学習法

こちらをpytorchを使用してレイヤとして実装しました。

おまけでとりあえずMNISTを丸ごと学習するスクリプトと、いくつかのモデルを用意しています。

devcontainerとtensorboardによる訓練のロギングまで実装しておいたので、実験してみてください。

## 実装した内容について

ED法を示した図を基に実装しました。

※転載の転載です[@Cartelet 金子勇さんのED法の解説と弱点、行列積を使用した効率的な実装](https://qiita.com/Cartelet/items/a18e32348adc0c689db4)
出典：https://web.archive.org/web/20000306212433/http://village.infoweb.ne.jp:80/~fwhz9346/ed.htm

![ed layer increase できれば直リンで貼りたいけど無理かもしれない](https://camo.qiitausercontent.com/8afaf94a8703b67297b658e773a7a967a8032494/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3530313238312f38353636313835322d623163652d386366392d363432302d3830313431656636346538352e706e67)




ED法の特徴を図から次のように捉え実装しました。
- 入力～出力までの経路が一意
    - 自身と１つ前の入力、出力からやってきた上げる・下げるの信号でその重みを調整する
- 誤差は全層で共有する
    - pytorchのbackwardの仕組みを使いながらも、最終層のgrad_outをバイパスすることで実現
- 層を全くごとに結合され、in/2個だけ次の出力が生まれる
    - 図を見る限りそうとしか考えられない
    - 最初に十分な数の入力複製を作成しておく
        - 通常のモデルであれば特徴量は段階ごとに増えるのとは対照的で面白いと思う
- 出力数を内積などで直接増やすことはできない
    - 入力と出力の関係が崩れ、誤差の共有ができなくなるため
    - 全層をそもそも十分に複製し、結合してしまうことで複数出力を実現している
        - 考え方的にはconv1dのgroupsに近い

もとのC実装は見たのですが、あんまり図のとおりに実装している気がしないので、いっそ図のほうに寄せて考えて実装しました。
なので、ちょっと変わっているかもしれません。

## 確認できていること
- 一番手前の層までgradが共有される
- 出力を10個に増やし、softmaxがかけられている
- なんとなく訓練されるっぽい
- 多分torchにできてるからcudaで動く（はず）

## 確認できていないこと
- ここまで実装したけどちゃんと訓練してログを見れてない
    - くそ重いので、注意してください（CPUで実行）
    - epoch100くらいまではなんかそれっぽくACCが上がるみたいです


## 実装できていること
- いくつかのbackwardをいじった関数の実装
- レイヤとしての実装
- 活性化関数を任意に差し替える方法

## 現状追加のアイデア
- 層をまたぐたびに減る分は、また入力を複製して作ってしまえば理論上無限に中間層を増やせるかもしれない

## ぜひ実験してください
- 実験結果や感想、改善案はIssueやコメント、プルリクでいただけると嬉しいです
PDO (PHP Data Objects)

## はじめに

PDOについてまとめる

### PDOとは

PHPのデータベース抽象化レイヤー。
データベース抽象化レイヤーはデータベース毎の違いを吸収し、アプリがデータベースに対応して何んらかのアクセスを試みる際に共通の手段を提供する。

### データベースへの接続

データベースへの接続を確立する

```php:connect.php
$dsn = 'mysql:dbname=testdb; host=127.0.0.1; charset=utf8';
$usr = 'testuser';
$passwd = 'testpass';

try {
    $dbh = new PDO($dsn, $usr, $passwd);
    echo '接続成功';
} catch (PDOException $e) {
    echo '接続失敗: ' . $e->getMessage();
} finally {
    $dbh = null;
}
```

### PDOクラス
```php
new PDO(string $dsn [, string $username [, string $password [, array $options]]])

$dsn : データベース接続文字列
$username : データベースのユーザー名
$password : データベースのパスワード
$options : 接続オプション
```

### データベース接続文字列

データベース接続文字列は、データベースに接続するための情報を一定の書式でまとめたもの。
書式は接続先のデータベースによって異なる。

### 接続オプション

データベース接続時の挙動を決めるパラメーター情報のこと。
PDOクラスをインスタンス化する場合に連想配列[オプション名 => 設定値]の形式で指定するか、setAttributeメソッドを使って個別に設定できる。
suzume-llama-3-8B-japaneseは『雪国』の冒頭をどうトークナイズするのか

[Lightblue](https://www.lightblue-tech.com/category/news/)から「[suzume-llama-3-8B-japanese](https://huggingface.co/lightblue/suzume-llama-3-8B-japanese)」という日本語モデルがリリースされたので、早速トークナイザを試してみることにした。

```
>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("lightblue/suzume-llama-3-8B-japanese")
>>> print(tkz.convert_ids_to_tokens(tkz("国境の長いトンネルを抜けると雪国であった。","夜の底が白くなった。")["input_ids"]))
['åĽ½', 'å¢ĥ', 'ãģ®', 'éķ·', 'ãģĦ', 'ãĥĪ', 'ãĥ³ãĥ', 'į', 'ãĥ«', 'ãĤĴ', 'æĬľ', 'ãģĳ', 'ãĤĭãģ¨', 'éĽª', 'åĽ½', 'ãģ§ãģĤãģ£ãģŁ', 'ãĢĤ', 'å¤ľ', 'ãģ®', 'åºķ', 'ãģĮ', 'çĻ½', 'ãģıãģª', 'ãģ£ãģŁ', 'ãĢĤ']
```

う、そのパターンは「[Meta-Llama-3-8B](https://huggingface.co/meta-llama/Meta-Llama-3-8B)」と[全く同じ](https://qiita.com/KoichiYasuoka/items/d562e35fe61d8028000d)…

```
>>> text="国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。"
>>> x=tkz(text,return_offsets_mapping=True)
>>> for i,(s,e) in zip(x["input_ids"],x["offset_mapping"]):
...   print(text[s:e],text[s:e].encode("utf-8"),ascii(tkz.convert_ids_to_tokens(i)))
...
国 b'\xe5\x9b\xbd' '\xe5\u013d\xbd'
境 b'\xe5\xa2\x83' '\xe5\xa2\u0125'
の b'\xe3\x81\xae' '\xe3\u0123\xae'
長 b'\xe9\x95\xb7' '\xe9\u0137\xb7'
い b'\xe3\x81\x84' '\xe3\u0123\u0126'
ト b'\xe3\x83\x88' '\xe3\u0125\u012a'
ンネ b'\xe3\x83\xb3\xe3\x83\x8d' '\xe3\u0125\xb3\xe3\u0125'
ネ b'\xe3\x83\x8d' '\u012f'
ル b'\xe3\x83\xab' '\xe3\u0125\xab'
を b'\xe3\x82\x92' '\xe3\u0124\u0134'
抜 b'\xe6\x8a\x9c' '\xe6\u012c\u013e'
け b'\xe3\x81\x91' '\xe3\u0123\u0133'
ると b'\xe3\x82\x8b\xe3\x81\xa8' '\xe3\u0124\u012d\xe3\u0123\xa8'
雪 b'\xe9\x9b\xaa' '\xe9\u013d\xaa'
国 b'\xe5\x9b\xbd' '\xe5\u013d\xbd'
であった b'\xe3\x81\xa7\xe3\x81\x82\xe3\x81\xa3\xe3\x81\x9f' '\xe3\u0123\xa7\xe3\u0123\u0124\xe3\u0123\xa3\xe3\u0123\u0141'
。 b'\xe3\x80\x82' '\xe3\u0122\u0124'
夜 b'\xe5\xa4\x9c' '\xe5\xa4\u013e'
の b'\xe3\x81\xae' '\xe3\u0123\xae'
底 b'\xe5\xba\x95' '\xe5\xba\u0137'
が b'\xe3\x81\x8c' '\xe3\u0123\u012e'
白 b'\xe7\x99\xbd' '\xe7\u013b\xbd'
くな b'\xe3\x81\x8f\xe3\x81\xaa' '\xe3\u0123\u0131\xe3\u0123\xaa'
った b'\xe3\x81\xa3\xe3\x81\x9f' '\xe3\u0123\xa3\xe3\u0123\u0141'
。 b'\xe3\x80\x82' '\xe3\u0122\u0124'
```

ああ、「トンネル」が3バイト・5バイト・1バイト・3バイトの4トークンにブッタ切られている。「抜」「け」「ると」とか「白」「くな」「った」とかも、そのままほったらかしで、日本語トークナイザとしてはヒドイ状態だ。これだと日本語の精度が上がらないと思うのだけど、実際のところ、どうなんだろう。
【MySQL】インストール～テーブル作成まで

# はじめに
### 背景
　WebアプリケーションをJavaのSpring Bootで作成することになり、データベースなどを1から準備することになったので、記事にまとめてみました。
### この記事でわかること
* MySQLのインストール
* ユーザーの作成、権限の付与
* データベース、テーブルの作成


### MySQLのインストール
　インストールや初期設定には以下の記事を参考にさせていただきました。

https://qiita.com/aki_number16/items/bff7aab79fb8c9657b62

　基本的にはデフォルトの設定でOKですが、ルートアカウントのパスワードの設定が必要なので注意が必要です。

### ユーザーの作成、権限の付与
　MySQLのインストールしたら、管理者権限でコマンドプロンプトを開き、ルートユーザーにログインします。

```
mysql -u root -p
```
　パスワードを聞かれるので、インストール時に設定したパスワードを入力するとログインできます。
　以下の文でユーザーの作成を行います。
```
--ユーザ作成とパスワード設定
CREATE USER 'ユーザー名'@'localhost' IDENTIFIED BY 'パスワード';
```
　作成したばかりのアカウントには権限が付与されていないので、データベース作成、テーブル作成などができません。ルートアカウントの状態で権限を付与します。
```
--全ての権限の付与
GRANT ALL ON *.* TO 'ユーザー名';
```
今回は全ての権限を付与しました。

試しに作成したユーザーでログインしてみましょう。
```
mysql -u 'ユーザー名' -p
```

サンプル用のデータベースを作成します。
```
CREATE DATABASE sampledb;
```
Query OKと出力されれば成功です。

次にテーブルを作成します。
```
CREATE TABLE sampledb.Sample (
    Id int(5) NOT NULL PRIMARY KEY,
    Memo varchar(200)
);
```
Query OKと出力されれば成功です。

以上で、MySQLの環境の準備が完了しました。


ユーザーの作成、権限の付与などは以下の記事を参考にさせていただきました。

https://qiita.com/gatapon/items/92b942fa7081cfe17482


https://www.javadrive.jp/mysql/user/index6.html#google_vignette



# まとめ
　今回はMySQLのインストールからテーブルの作成までをまとめました。
世界一流エンジニアの思考法

# 概要
[こちら](https://qiita.com/asukitt/items/1eee0b9517e34a91d99e)の記事にもある通り、技術力を上げるためにエンジニアに関する書籍や技術書を1か月に1冊読んでいます。
今まで読んだ本はこちら
・[2冊目(Docker系)](https://qiita.com/asukitt/items/b96cb182eaafe9eeb28d)
・[3冊目(読みやすいコードの書き方)](https://qiita.com/asukitt/items/ae96838bc2f48b7c6de3)


# 今回の書籍
Qiitaで技術書のおすすめを探している時に面白そうだなと思いすぐ購入しました。
今回は技術書ではなく、仕事をする上で使える思考法が詰め込まれている本にしました。
それが[こちら](https://www.amazon.co.jp/%E4%B8%96%E7%95%8C%E4%B8%80%E6%B5%81%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E6%80%9D%E8%80%83%E6%B3%95-%E7%89%9B%E5%B0%BE-%E5%89%9B/dp/4163917683)です。
![エンジニア.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957298/63041fd3-30fb-b95d-d774-172828c4f2c8.jpeg)



元々三流のプログラマだった著者が、マイクロソフトで一緒に働く天才エンジニア達の仕事ぶりを見て、発見した思考法をまとめています。
思考法に到達するまでの背景も体験談付きでとても読み進めやすいです。

# 仕事で活かしたいもの
読んでいる中で仕事に活かしたい思考法があったので下記にまとめます。

### エラー時の対応
事実を1つ見つける→仮説をいくつか立てる→検証
***※思いつくままに試行錯誤するのは悪***

### 理解に時間をかける
・どんなに頭がいい人でも理解に時間がかかる
・調べながら使うよりも、調べずに使えるように理解する方が最終的な生産性は高くなる

***理解の定義***
1.説明可能
2.応用可能
3.いつでも使える

### メンタルモデルを作る
メンタルモデル：考えの偏りをなくすために、理解→予測→解釈を行い新しい状況に適用するための自己の心の中のイメージや理論
***これはまだ自分には無いので調べて作ろうと思う***

### Be Lazyのマインド
より少ない時間で価値を最大化する→時間を固定化して、成果を最大化

### 失敗を恐れない
・早いうちに失敗することが、後の大きな失敗を減らす
・失敗を批判しない雰囲気作り（マネジメント側になったらやりたい）

### コードの読み方
端から端まで読む→構造理解を心掛け脳の負荷減らす

### マルチタスクをやめる
***最終的な生産性は40%低下、時間は50%増加する***
・１つのタスクをやると決めたら、作業中は他のタスクはやらない
・30~１時間の時間を割り当て、切り上げる時はメモを残してすぐに再開できるようにする

### 記憶力・理解力の向上方法
・後で人に説明するのを前提で学ぶ・聞くを行う
・技術ブログは既存のコードのコピペではなくアレンジして載せるようにする

### コミュニケーションの極意
相手の意見を否定しない

### ワークライフバランス
・定時で上がる意識を持ち時間内の成果を最大化→学習の時間を増やし長い目での効率化

### 脳の疲労をためない方法
・5~10分の瞑想
・ディスプレイから離れる時間を作る
・睡眠時間の確保

***人間は同じことに４時間以上集中できない***

### 人生をコントロールする感覚
×成功が幸福をもたらす
〇幸福が成功をもたらす

***幸福感を感じやすい環境作り***
1.部屋をきれいに片付ける→何かをしたら完了するまでやる
2.運動をしてテストステロン出す（しんどいのは続かないからできる範囲で）

# まとめ
このように当たり前のことかもしれないが、つい忘れてしまっていることが多々あった。
これらを意識して毎日過ごすことの積み重ねが自分の将来を作るということが分かった。
全部一気にできなくても良い、ちょっとずつでもいいのでここに書いていることを読み返しながら日々過ごしてみようと思う。
すぐにできる部屋の整理や運動はやってみたが頭がすっきりする感覚があったのでおすすめ！
***仕事で大事にしたいのは、理解の範囲を拡大すること・やみくもに試行錯誤しないこと***
【Next.js】ボタンのデザインを変えたいが修正箇所が分からない人へ

# 対象読者
**Next.jsでボタンのデザインの変えたいが、どこを修正すればよいか分からない人**

# 前提
**・ Next.jsの雛形は作成済み**

# やり方
以下のコマンドを実行
```
npx shadcn-ui@latest add button
```

button.tsxが作成される。

variant部分に作りたいボタンのcssを書いていく。
![スクリーンショット 2024-04-25 20.03.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1850625/28d96018-c911-2191-4266-c732b43a5ae1.png)

variantに追加した名称（primaryなど）を、Buttonコンポーネントのプロパティとして渡すことでそのデザインが適用される。
![スクリーンショット 2024-04-25 20.05.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1850625/b5771603-aaed-325a-82fd-e489867a529a.png)
※ Secondary Buttonにはprimaryで指定したcssが反映される。

↓ こんな感じ
![スクリーンショット 2024-04-25 20.11.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1850625/42ce0fc6-0aee-ef0e-34a3-66990df6474e.png)

primaryとdestructiveのcssは以下のように指定している。
```tsx:button.tsx
primary: 
    "bg-sky-400 text-primary-foreground hover:bg-sky-400/90 border-sky-500 border-b-4 active:border-b-0",
destructive:
    "bg-green-500 text-destructive-foreground hover:bg-destructive/90",
```

以下の動画の、**Buttons library**の章で詳しく解説されているので良ければ参考までに　↓
https://www.youtube.com/watch?v=dP75Khfy4s4&t=737s
～ 辞書 ～ チートシート

#目次
[要素の削除](#要素の削除)　`.pop()`　`del dict[]`
[リストに抽出](#リストに抽出)　`list(dict.keys())`　`list(dict.values()))` `list(dict.items()))`

[要素の追加](#要素の追加)　`.setdefault()`　`dict[]`
[要素の参照](#要素の参照)　`.get()`　`dict[]`

#はじめに

チートシートの扱いついては[ここ](https://qiita.com/ysys_Ba/items/d27282b888abbd1f43e7#%E3%83%81%E3%83%BC%E3%83%88%E3%82%B7%E3%83%BC%E3%83%88%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)を読んでください

#要素の削除

```python:dict.py
dict = {"Oto" : 9, "Ura" : 9, "Niji" : 12, "Yui" : 11, "Hasu" : 9}
print(dict.pop("Oto"))
print(dict)
```

```python:mat
>>> 9
>>> {"Ura" : 9, "Niji" : 12, "Yui" : 11, "Hasu" : 9}
```

`.pop()`で指定したキーの要素を渡し、削除も可能

```python:dict.py
dict = {"Oto" : 9, "Ura" : 9, "Niji" : 12, "Yui" : 11, "Hasu" : 9}
del dict["Oto"]
print(dict)
```

```python:mat
>>> {"Ura" : 9, "Niji" : 12, "Yui" : 11, "Hasu" : 9}
```

`del`で指定したキーの要素を削除できる

#リストに抽出

```python:dict.py
dict = {"Oto" : 9, "Ura" : 9, "Niji" : 12, "Yui" : 11, "Hasu" : 9}
print(list(dict.keys()))
```

```python:mat
>>> ['Oto', 'Ura', 'Niji', 'Yui', 'Hasu']
```

`list(dict.keys())`でキーのみを抽出し配列にできる

```python:dict.py
dict = {"Oto" : 9, "Ura" : 9, "Niji" : 12, "Yui" : 11, "Hasu" : 9}
print(list(dict.values()))
```

```python:mat
>>> [9, 9, 12, 11, 9]
```

`list(dict.values())`で要素のみを抽出し配列にできる

```python:dict.py
dict = {"Oto" : 9, "Ura" : 9, "Niji" : 12, "Yui" : 11, "Hasu" : 9}
print(list(dict.items()))
```

```python:mat
>>> [('Oto', 9), ('Ura', 9), ('Niji', 12), ('Yui', 11), ('Hasu', 9)]
```

`list(dict.items())`でキーと要素の両方を抽出し配列にできる
キーと要素の組はリストではなくタプルであることに注意
C#で知らなかった補完された生文字リテラルのTips

# C#で知らなかった生文字リテラルの利用方法

以下のMicrosoft公式のドキュメントを読めば一発なんですが、知らなかったのでTipsとして投稿します。
<https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/tokens/interpolated#interpolated-raw-string-literals>

生文字リテラルはC#におけるダブルクォーテーション3つで囲んだ文字列のことをいいます。
生文字リテラルを利用すれば、特殊文字をそのまま文字列として扱います。

```csharp
var message = """このように書くと特殊文字列の{}とかがそのままかけます""";
```

そしてドルマークをつけることで変数が埋め込めるのも知っている方もいるかと思います。

```csharp
var x = "「テストです」";
var message = $"""$マークを先頭につけることで変数x:{x}がそのまま埋め込めます""";
```

自分が知らなかったのは、生文字リテラルの場合、さらにドルマークの数を増やすことで変数を埋め込むときに必要な波括弧の数を増やすことができます。

```csharp
var x = "「テストです」";
var message = $$"""$マークが2つの場合、変数を埋め込みたいなら波括弧{}を2つ続けます。変数x:{{x}}""";
```

活用するポイントは多くないかもしれませんが、知っていたら便利かもしれません。
また、知らないことがあればTipsとして投稿したいと思います。
Pythonのpyttsx3のNameErrorの対処

音声読み上げてくれるアプリを作りたかったので調べる。

https://nekonogorogoro.com/pyttsx3_speak_jugemu/

↑これを参考にしてpyttsx3モジュールを使い音声を読み上げさせる。
```py
import pyttsx3
engine = pyttsx3.init()
engine.say("I will speak this text")
engine.runAndWait()
```
```
NameError: name 'objc' is not defined
```
オブジェクトが見つからないので調べる。
# 解決
参考

https://stackoverflow.com/questions/77197398/error-running-pyttsx3-code-on-os-x-nameerror-name-objc-is-not-defined

「py3-tts のインストールに従ったところ、ダミーパラメータなしで動作するようになりました。」
と記載してあったのでpy3-ttsをダウンロード。
```
$ pip install py3-tts
```
無事音声が使えるようになりました！！


なぜ使えるようになったか？公式の説明を見てみると...

**pyttsx3 2.90
Python 2 および 3 用の Text to Speech (TTS) ライブラリ。インターネット接続や遅延なしで動作します。 Sapi5、nsss、espeak などの複数の TTS エンジンをサポートします**

**py3-tts 3.5
Python 3 の Text to Speech (TTS) ライブラリ。インターネット接続や遅延なしで動作します。 Sapi5、nsss、espeak などの複数の TTS エンジンをサポートします**

自分のインストールしたpyttsx3がpython3.8には対応していなかったことが原因？
即時関数について

### 即時関数とはこういったもの

```jsx
(function () {
  console.log('called.');
})();
```

### 即時間数の使い道

関数スコープを用いて、関数の中だけで使いたいものと、関数の外側で使いたいものを明確に区別するときに使う。

```jsx
let c = (function () {
  console.log('called.');

  // private変数
  let privateVal = 0;
  // public変数
  let publicVal = 10;

  // private関数（外から呼び出せない）
  function privateFunc() {
    console.log('privateFunc is called.');
  }
  // public関数（外から呼び出せる）
  function publicFunc() {
    console.log('publicFunc is called.' + privateVal++);
  }

  privateFunc();

  // privateValとpublicFuncを外から呼び出せるようにする。
  return {
    // オブジェクトリテラル
    // 本来、変数: プロパティ名
    // だが、変数名とプロパティ名が同じ時はプロパティ名省略可能
    publicVal,
    publicFunc
  }
})();

c.publicFunc();
c.publicFunc();
c.publicFunc();
c.publicFunc();
console.log(c.publicVal);
```

### 参考

**【JS】ガチで学びたい人のためのJavaScriptメカニズム**

https://www.udemy.com/course/javascript-essence/?couponCode=ST6MT42324
MetaQuest3とUnityでMRを始めよう

### 手順

1. 3Dでプロジェクトを作る
2. Edit → Project Setting → XR Plugin Management → install
3. PCとAndroidのOculusにチェック
4. Oculus Integrationをインストール → UnityAppを開く
5. Oculus Integrationをimport → 全ての項目にYes
6. Oculus → Tool → Project Setup Tool → PCとAndroidをAll fix & All Apply
7. File → Build Settings → AndroidにSwitch Platform

### カメラの設定

1. MainCameraをDelete
2. Assetの検索 → OVRCameraRigの２個目をHierarchyにドロップ

### コントローラー

1. Assetの検索 → OVRControllerPrefab をOVRCameraRigの子要素Left,RightどちらとものHandAnchor内のControllerAnchorにドロップ
2. OVRControllerPrefab内のControllerをそれぞれL Touch, R Touchに
3. Assetの検索 → OVRHandPrefab をOVRCameraRigの子要素Left,RightどちらとものHandAnchorにドロップ
4. RightのOVRHandPrefabのHandType，SkeletonType，MeshTypeをHandLeftからHandRightに

### パススルー

1.  Hierarchy → Create Empty → Add Component → OVRPassthroughLayer
2. OVRCameraRigの子要素CenterEyeAnchorのClearFlagsをSkyBoxからSolidColorにし，BackGroundを真っ黒に
3. OVRCameraRigのOVRManagerのTarget DevicesのQuest3にチェック
4. 同じくOVRManagerのHandTrackingSupportをControllersOnlyからControllers And Handsに
5. 同じくOVRManagerのPassthroughSupportをNoneからSupportedにし，EnablePasstjroughにチェック

### 起動

1. SceneInBuildにSampleSceneを追加する
2. BuildSettingからDevicesをOculusにして，Build＆Run
多重minify

異なるminifierでminifyを繰り返すと、より縮む可能性があります。ただし時代についていけていないminifierもあります。そういうものを使うと不具合が出る事があるで注意して下さい。
## JavaScript用
一撃目にClosure Compiler、続けて他のminifierを叩き込むのが良いかもしれません

* [butternut](https://github.com/Rich-Harris/butternut)
* [babel-minify](https://github.com/babel/minify)
* [Closure Compiler](https://github.com/google/closure-compiler)
* [terser](https://github.com/fabiosantoscode/terser)([demo](https://try.terser.org]))
* [UglifyJS](https://github.com/mishoo/UglifyJS2)

## CSS用
一撃目にcssnano、続けて他のminifierを叩き込むのが良いかもしれません

* [clean-css](https://github.com/jakubpawlowicz/clean-css)([demo](https://clean-css.github.io/))
* [crass](https://github.com/mattbasta/crass)
* [csso](https://github.com/css/csso)([demo](https://css.github.io/csso/csso.html))
* [cssnano](https://github.com/ben-eb/cssnano)([playground](https://cssnano.github.io/cssnano/playground/))
* [Lightning CSS](https://github.com/parcel-bundler/lightningcss)([playground](https://lightningcss.dev/playground/index.html))
Goで簡易なコマンドラインセレクタを作りました。

## 作成したもの
RustでCLIのメモツールを作成する際、メモ一覧を表示して選択する機能が欲しいと考え、簡易なコマンドラインセレクタを作成いたしました。

本当はRustで作成したかったのですが、[Ratatui](https://ratatui.rs/)などのTUIツールをうまく使いこなすことができなかったため、Goで書くことにしました。

GoのTUIライブラリである[tview](https://github.com/rivo/tview)は非常に使いやすく、簡単に作成することができました。

mattnさんの[cho](https://github.com/mattn/cho)にとても影響を受けており、かなり簡易な作りにしてあります。   
（mattnさんのchoはWindowsでも使えるため、高度な実装をしていると思います。）

## 使い方
slctは、標準入力から受け取った文字列を改行で区切り、それを選択肢として表示することを目的としていますので、単体で使うことはまずないと思います。   
実際に使用する際は、lsやfindなどのコマンドとパイプラインを組み合わせて使用することを想定しています。

例えば、以下のように使用できます。

```sh
ls -a | sclt
```

[![asciicast](https://asciinema.org/a/AIV5gUgisQSdHU0TwroGUVAnK.svg)](https://asciinema.org/a/AIV5gUgisQSdHU0TwroGUVAnK)

この処理は`ls -a`で取得したファイル一覧を`slct`に渡し、選択したファイル名を標準出力に出力しています。

もう一つ挙げますと、以下のように使用できます。

```sh
cd $(ghq list --full-path | slct)
```

[![asciicast](https://asciinema.org/a/xFTzNG7oktfCuT9Idbl3xa2oA.svg)](https://asciinema.org/a/xFTzNG7oktfCuT9Idbl3xa2oA)

この処理は[ghq](https://github.com/x-motemen/ghq)というリポジトリ管理ツールで管理しているリポジトリ一覧を`slct`に渡し、選択したリポジトリのパスを標準出力に出力しています。   
（非常に便利なため、筆者は愛用しています。）

## 実装内容

1. tviewの`NewTable`を使用して、選択肢を表示するためのテーブルを作成します。

```go
app := tview.NewApplication()

table := tview.NewTable().SetSelectable(true, false)
```

2. 標準入力から行を読み取り、それぞれを新しいセルとして表に追加します。このプロセスは、標準入力からの入力がなくなるまで続けます。

```go
scanner := bufio.NewScanner(os.Stdin)
row := 0

for scanner.Scan() {
	line := scanner.Text()
	cell := tview.NewTableCell(line).SetSelectable(true)
	table.SetCell(row, 0, cell)
	row++
}
```

3. ユーザーが表のセルを選択したときの動作を定義します。選択されたセルのテキストが表示され、アプリケーションが停止します。

```go
table.SetSelectedFunc(func(row, column int) {
	cell := table.GetCell(row, 0)
	app.Stop()
	fmt.Println(cell.Text)
})
```

4. ユーザーが 'q' を押したときにアプリケーションが停止するように設定します。

```go
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
	if event.Key() == tcell.KeyRune && event.Rune() == 'q' {
		app.Stop()
	}
	return event
})
```

5. 選択されたスタイルを設定し、ステータスバーを作成し、それを表とともにフレックスレイアウトに追加します。

```go
table.SetSelectedStyle(tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack))

statusBar := tview.NewTextView().SetText("Press 'q' to exit").SetTextAlign(tview.AlignLeft).SetTextColor(tcell.ColorYellow)

flex := tview.NewFlex().SetDirection(tview.FlexRow).AddItem(table, 0, 1, true).AddItem(statusBar, 1, 0, false)
```

6. アプリケーションを実行します。

```go
if err := app.SetRoot(flex, true).Run(); err != nil {
	fmt.Fprintf(os.Stderr, "Error running application: %v\n", err)
	os.Exit(1)
}
```

## 今後の予定
考えられる改修点をいくつか挙げますと、以下のようなものがあります。

- [ ] テストの追加
- [ ] インクリメンタルサーチの追加
- [ ] config.yamlで設定を変更できるようにする
- [ ] 複数選択に対応する

テストの追加は早めに行う必要があると考えており、config.yamlでの設定変更も文字に色をつけるだけでも実装しようと思っています。

ただ、インクリメンタルサーチと複数選択に関しては、そこまでフォローするくらいなら大人しく[peco](https://github.com/peco/peco)を使った方が良いかもしれません。

時間があるときに文字色だけでも変更できるように実装しておきたいと思います。

## おわりに
メモツールを作成する前段階が完了しました（長かったです...）ので、次はメモツールの作成に取り掛かりたいと思います。

GoでCLIツールを作成するのは非常に楽しいです。   
また、自作ツールがかなり便利で使用頻度が高いのも楽しいです。