OmniAICreator/Qiita-1.07M huggingface dataset:
github管理の始め方・使い方

github管理の始め方や普段使っていないコマンドが慣れず、迷子になったので備忘録。
（gitの使い方も含みます）

# GitHub管理の始め方
- githubリポジトリを作成
- ターミナルにてgit管理したい階層まで``cd``
- リポジトリ作成した、github画面に出ているコマンドを順番に打ち込む

## ※ ライブラリ・フレームワークによっては導入時点でgitがインストールされている場合もある。
例）Reactなど
その場合は、以下でリポジトリと紐付け可能。
- githubリポジトリを作成
- ``git remote add origin https://github.com/（githubユーザー名）/（リポジトリ名）.git``
- ``git push -u origin （ブランチ名）``

# Githubユーザー名・アドレスを確認する方法
※個人アクセストークン発行時に入力を求められる（https接続時）

- ユーザー名  ``git config user.name``

- アドレス ``git config user.email``

・【参考】個人アクセストークンを使用する
https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token

# 指定コミットまで戻す方法
パッケージをアンインストールしたり、インストールしたりでフレームワーク（React）を壊して画面表示がされなくなったため、コミットを戻した。

- ``git log``でコミットidを確認
- ``git reset --hard (コミットid)``

#### ※これですぐに戻る。``git status``をしても差分検知はされていなかった。

# ブランチを削除する
#### ※【前提】該当ブランチに自身がいないこと
``git branch -d （ブランチ名）``
【初心者】LinuxでDVDを制作する

# 自作の動画ファイルをDVDで保存したい

例えば、ホームビデオで撮影した動画などを、高齢の両親に見せたい場合、動画ファイルを再生してもらうのは敷居が高いことがあります。

そうした時、DVDに焼いて郵送したいと思ったのですが、イメージファイルを作成するのに試行錯誤しましたのでまとめます。

XXX.mp4をイメージにするとします。ユーザー環境でいいです

```
% export VIDEO_FORMAT=NTSC
% mkdir DVD_DIR
% ffmpeg -i XXXX.mp4 -target ntsc-dvd XXX.mpg
% dvdauthor -t -o DVD_DIR -f XXX.mpg
% dvdauthor -o DVD_DIR -T
% mkisofs -dvd-video -o IMAGE.iso DVD_DIR
% brasero IMAGE.iso
```
Microsoft PowerBI Desktopで、リレーションシップ設定（カラムの紐づけ）

記載日：2022/4/3
PowerBI Desktopで、リレーションシップの設定方法を記載します。
なお、リレーションシップ設定のやり方は２パターンあります。設定画面を使うやり方と絵を使うやり方です。
（リレーションシップ：異なるフィールド（テーブル）にあるカラム同士を紐づけること。）

#### 目標
リレーションの作成。

#### 作業（設定画面を使う場合）
０．フィールド作成
　データを読み込む。フィールドにデータが表示される。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/4ad5113b-3258-fd26-2717-14cd8a7a3a12.png" width=20%>

１．リレーションシップ設定
　対象のフィールド上で右クリックし”リレーションシップの管理”を選ぶ。
　リレーションシップの管理画面が表示されるので”新規”ボタンを押す。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/9d817a63-b0be-e518-ac1e-f0b630dff1cd.png" width=20%>

　１つ目のセレクタで親フィールドを選択し、２つめのセレクタで子フィールドを選択する。
　１つ目の表で、リレーションシップを設定したいカラムをクリックすると、”カーディナリティ”と”クロスフィルターの方向”を自動的に設定してくれる。
　”OK”ボタンを押す。リレーションシップが設定される。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/2b05fc13-e983-1353-7bcb-927088452384.png" width=80%>

　モデル画面（以下の画面切替ボタンの中の３つ目）を表示させるとリレーションシップが設定されたことを確認できる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/e6fde7a2-5ade-d7c3-efe5-dd308e03218e.png" width=5%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/92adfc8a-3d98-c544-f528-91f44d67442b.png" width=80%>

#### 作業（絵を使う場合）
０．フィールド作成
　データを読み込む。フィールドにデータが表示される。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/4ad5113b-3258-fd26-2717-14cd8a7a3a12.png" width=20%>

１．リレーションシップ設定
　モデル画面（以下の画面切替ボタンの中の３つ目）を表示させる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/e6fde7a2-5ade-d7c3-efe5-dd308e03218e.png" width=5%>

　親フィールドの中の紐づけたいカラムをドラッグし、子フィールドの中の紐づけたいカラムへドロップする。
　リレーションシップが設定される。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/1f1bae69-7272-2ae5-69cf-11d13ee8289d.png" width=80%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/c5bc303a-c5f7-7461-1f52-74ecf95d705c.png" width=80%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1381309/3551561d-4d2f-234d-51f4-a3cec406dccf.png" width=80%>

#### 参考
上記作業で使用したデータサンプルを以下に記載する。

企業テーブル用データ
~~~
Name,Country,StartedAt
TAYATO,Japan,1890
HANDO,Japan,1921
VLOV,Sweden,1834
Melsdez,Germany,1836
Tasle,USA,2005
Valkswegon,Germany,1839
GanarelMotors,USA,1838
~~~

売上テーブル用データ
~~~
Year,Company,Sales,Quantity
2019,TAYATO,302256,1005
2020,TAYATO,299299,929
2021,TAYATO,232670,727
2019,HANDO,149310,430
2020,HANDO,131705,375
2021,HANDO,106770,307
2019,VLOV,33906,61
2020,VLOV,32718,60
2021,VLOV,36133,63
2019,Melsdez,130705,305
2020,Melsdez,197070,500
2021,Melsdez,217305,670
2019,Tasle,26750,59
2020,Tasle,32892,71
2021,Tasle,61660,116
2019,Valkswegon,252632,823
2020,Valkswegon,287075,889
2021,Valkswegon,168777,487
2019,GanarelMotors,150780,457
2020,GanarelMotors,128425,245
2021,GanarelMotors,145700,350
~~~

#### 参考にさせて頂いたサイト
・リレーションシップについて
https://docs.microsoft.com/ja-jp/power-bi/transform-model/desktop-create-and-manage-relationships
Power BI Desktopで前日差を求める＜メモ＞DATEADD、PREVIOUSDAY関数

# 累積データ使用

日毎の累積データを扱う際、日ごとの増加分を算出したいと考えることがあります。
ただ、「Power BI Desktop」でその算出方法がわかりませんでした。
「DAX」を使えばできるのだろうと思ってましたが、何ぶんDAXの知識が不足しており手付かずでした。
ちょっとしたがきっかけでできたので、メモを残すことにしました。

使用したデータは内閣官房が「新型コロナウイルス感染症対策」サイトで提供しているオープンデータです。

https://corona.go.jp/dashboard/

下記のようなデータを使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/1a61f12f-1fdf-d3a6-5c2f-6698699a7f0b.png)

# DATEADD利用例

**DATEADD**：指定された間隔数だけ時間を前後にシフトした日付の列を含むテーブルを返します。
https://docs.microsoft.com/ja-jp/dax/dateadd-function-dax

●前日の値（メジャー）
「-1」で前日の累積値（culm）を返す。
階層型（年・四半期・月・日）の日付値を使う。
「[date].[Date]」は階層の中から「日」を使うという指定。
~~~
Pre_DATEADD = 
		CALCULATE(
			SUM('前日差_メモ用'[culm]),
			DATEADD('前日差_メモ用'[date].[Date], -1, DAY)
		)
~~~

●前日との差（メジャー）
~~~
culm- Pre_DATEADD = 
		SUM('前日差_メモ用'[culm]) - [Pre_DATEADD]
~~~

# PREVIOUSDAY利用例

**PREVIOUSDAY**：dates 列内の最初の日付の前日を表すすべての日付の列を含むテーブルを返します。
https://docs.microsoft.com/ja-jp/dax/previousday-function-dax

●前日の値（メジャー）
DATEADDデー指定したように「-1」は使わない。
~~~
Pre_PREVIOUSD = 
		CALCULATE(
			SUM('前日差_メモ用'[culm]),
			PREVIOUSDAY('前日差_メモ用'[date].[Date])
		)
~~~

●前日との差（メジャー）
~~~
culm- Pre_PREVIOUSDAY = 
		SUM('前日差_メモ用'[culm]) - [Pre_PREVIOUSD]
~~~

結果は末尾に掲示します。

# 「列」の場合

「前日との差」は、表で考えると、行単位で計算するので（下記の表参照）、「メジャー」でなく「列」で算出できると考えました。
しかし、以下の式では想定通りの結果は得られませんでした。

●前日との差（列）
~~~
列_culm- Pre_DATEADD = 
		('前日差_メモ用'[culm]) - [Pre_DATEADD]
~~~

「[Pre_DATEADD」はメジャーなので、行単位ではなくテーブルを対象とし、指定した条件に沿う値を計算して返します。
メジャーであるPre_DATEADDで指定したフィルター条件（DATEADD('前日差_メモ用'[date].[Date], -1, DAY）は、数式列では有効にならなかったように思えます。
要因を理解しきれていないのですが、メジャーのロジックを列に割り当てるのは無理な感じはしました。

# 循環依存エラー対処1

なお、同様に「Pre_PREVIOUSD」の式を追加するとエラーが出ました。

●前日との差（列）
~~~
列_culm- Pre_PREVIOUSD = 
		('前日差_メモ用'[culm]) - [Pre_PREVIOUSD]
~~~

><pi>循環依存が検出されました: 前日差_メモ用[列_culm- Pre_PREVIOUSD], 前日差_メモ用[列_culm- Pre_DATEADD], 前日差_メモ用[列_culm- Pre_PREVIOUSD]。</pi>

「Pre_DATEADD」を使った式と同じスタイルなのに、なぜこのメッセージが出るのがわかりませんでした。
検索したところ、英語のサイトにたどり着きました。

https://www.sqlbi.com/articles/understanding-circular-dependencies/

この内容もあまり理解できなかったのですが、「CALCULATE関数を使った2つのメジャー関数がともに同じテーブル（'前日差_メモ用'[culm]）を参照していること。各メジャーを2つの数式列（列_culm- Pre_DATEADD、列_culm- Pre_PREVIOUSD）が使っていること」が関係しているようです。

上記サイトを参考に、以下の記述で対処しました。

●前日との差（列）
~~~
列_2culm- Pre_PREVIOUSD = 
		CALCULATE(SUM('前日差_メモ用'[culm]) - [Pre_PREVIOUSD], 
				ALLEXCEPT('前日差_メモ用', '前日差_メモ用'[date].[Date]))
~~~

エラーが出なくなっただけでなく、メジャーで使ったフィルター条件が適用できるようになりました。

# 循環依存エラー対処2
**ALLEXCEPT**：指定した列に適用されているフィルターを除く、テーブル内のすべてのコンテキスト フィルターを削除します。
https://docs.microsoft.com/ja-jp/dax/allexcept-function-dax

上述の通り、（たぶん）「ALLEXCEPT」を使うことで、「列」においても「メジャー」で使われているフィルターのみを有効にできるようです。

DATEADDを使っている数式列にも通用しました。

●前日との差（列）
~~~
列_2culm- Pre_DATEADD = 
		CALCULATE(SUM('前日差_メモ用'[culm]) - [Pre_DATEADD], 
				ALLEXCEPT('前日差_メモ用', '前日差_メモ用'[date].[Date]))
~~~

# 計算結果

集計初日の前日差は「その日の値-ゼロ」となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/0dda2780-5c84-eafd-7c28-5c65de4d3dca.png)

「Pre_DATEADD」を「空白でない」数値を表示するようにすれば、その値を表示しないようにできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/42a3b83e-33a6-4da7-3e74-548fcf425d94.png)

**了**
3byteのリセットコマンド(PC-98)

# PC-98
# ３バイトのリセットコマンドの中身

ずいぶん前にどこからか拾ってきたリセットコマンドはたったの３バイト。
どんな中身か調べてみた。

sdasm.exeで逆アセンブルした。いつまでも逆アセンブルが終わらないので、途中でctrl+Cして出力されたものをVzで追ったら下のような部分があった。
```
1E61:0100 E6F0                  out     0F0h,al 
1E61:0102 1A00                  sbb     al,[bx+si] 
```
この２行をもとにつぎのようなコードを作成し、アセンブラにかける。

> 開発環境
> Turbo Assembler  Version 2.0  Copyright (c) 1988, 1990 Borland International
:::
```C:r7.asm
;;;  r7.com
code segment
	assume cs:code, ds:code
	org 100h
start:
	out 0f0h,al
	sbb al,[bx+si]
code ends
end start
```

すると、４バイトのcomファイルができる。
逆アセンブルしても、結果は一緒。
```
1E61:0100 E6F0                  out     0F0h,al 
1E61:0102 1A00                  sbb     al,[bx+si] 
```
unixtoolのodでダンプすると、やっぱり一緒。
でも、r7.comは２行目が４になっている。
```
A:\>od -x r7.com
0000000  f0e6 001a
0000004

A:\>od -x r.com
0000000  f0e6 001a
0000003
```

r7.comをedix.comでダンプすると次のようになった。
```
segoffset +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  sum 0123456789abcdef
3E53:0000 E6 F0 1A 00 00 00 00 00-00 00 00 00 00 00 00 00  :F0 跼..............
---------------------------------------------------------------
check_sum E6 F0 1A 00 00 00 00 00 00 00 00 00 00 00 00 00  :F0
```
r.com（３バイト）をedix.comでダンプすると、
```
segoffset +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  sum 0123456789abcdef
3E7D:0000 E6 F0 1A 00 00 00 00 00-00 00 00 00 00 00 00 00  :F0 跼..............
---------------------------------------------------------------
check_sum E6 F0 1A 00 00 00 00 00 00 00 00 00 00 00 00 00  :F0
```
やっぱり同じに見える。
でも、vzで読み込むと、４バイトのほうは次のようになっている。
（^Z^@は制御文字）
```
跼^Z^@
```
３バイトのほうは
```
跼
```
の１文字だけ。
そこで、４バイトのほうをVzで読んで^Z^@を消して保存。
すると、ファイルサイズが３バイトになった。
```
-a--rwx       3 Apr  3 2022 16:18 r7b.com
```
このファイルを起動すると、無事（？）リセットされた。
【Javascript】配列内の重複要素を削除する

# はじめに
配列内の重複要素を削除する方法を備忘録として残しておきます。

# indexOfを使用する
```javascript
const array = [1, 2, 3, 4, 5, 1, 2, 1, 1, 4, 6, 7, 3]

const unique = array.filter((item, index) => {
  return array.indexOf(item) === index
})

console.log(unique); //=> [1, 2, 3, 4, 5, 6, 7] 
```

# new Setを使用する
```javascript
const array = [1, 2, 3, 4, 5, 1, 2, 1, 1, 4, 6, 7, 3]

const unique = [... new Set(array)]

console.log(unique); //=> [1, 2, 3, 4, 5, 6, 7] 
```

# どちらを使うべきか？
結論 `new Set`を使う。
以下の記事にもあるように、どちらでも重複要素を削除することは可能だが、fileterは配列内の要素数が多くなればなるほど処理が重くなるので、基本的には`new Set`で事足りるかなという印象です。

https://qiita.com/netebakari/items/7c1db0b0cea14a3d4419

# おわりに
もっと良い方法があれば教えていただけると幸いです。
スプライン vol.5 ～クロスバリデーション～

# 参考本
多変量解析入門　--線形から非線形へ--

小西貞則　著

# 前回記事

https://qiita.com/yudaiyamashita/items/b3057f0194a364b53b29

# モデルの評価と選択

正則化最小2乗法や正則化最尤法を用いてモデルを推定した場合、連続的に変化する平滑化パラメータの個々の値に対応して無限の異なったモデルが構成され、適切な平滑化パラメータの選択がモデリングの過程において必要となる。

正則化最尤法によってモデルを推定した場合には、
$\lambda$というパラメータを調整し、選択することになる。

$\lambda$を引数とするモデルの良さを評価するには・・・・

# モデルの有向自由度

B-スプラインなどの基底関数に基づく回帰モデルを用いた場合には、モデルの複雑さの程度は、平滑化パラメータに加えて基底関数の個数に依存する。

これは評価基準AICやBICを使用することが思い浮かぶ。

# クロスバリデーション）



平滑化パラメータや基底関数の個数の選択には、予測誤差の推定に用いられるクロス・バリデーション(交差検証法)という方法を用いる。

これは一組の観測データをモデルの推定に用いるデータとモデルの評価に用いるデータに分離して誤差の評価を行う方法で、次のように実行する。

モデルを$u(\boldsymbol y; \boldsymbol \omega)$と表すことにする。

First.
平滑化パラメータと基底関数の個数を事前に設定した後、$n$個の観測データの中から$i$番目の（プロット可能な２次元の）データ$(\boldsymbol x_i, y_i)$を除く残りの$(n-1)$個のデータに基づいて重みベクトル$\boldsymbol \omega$を推定し、これを$\hat{\boldsymbol \omega}^{(-1)}$とする。

Second.
次に、推定した回帰モデル$y=u(\boldsymbol x;u(\hat{\boldsymbol \omega}^{(-1)})$ に対して、取り除いたデータ$(\boldsymbol x_i, y_i)$での残差$y_i - u(\boldsymbol x;u(\hat{\boldsymbol \omega}^{(-1)})$を計算する。

このプロセスをすべてのデータに対して実行する。

$$CV(\lambda, m)= \displaystyle \frac{1}{n} \sum_{i}^{n}(y_i - u(\boldsymbol x;u(\hat{\boldsymbol \omega}^{(-1)}))^2$$

を求める。さまざまな平滑化パラメータの値と基底関数の個数に対してＣＶ値を最小とするモデルを最適なモデルとして選択する。

参考
Third. 一般化

$$\rm{GCV}(\lambda, m)=\displaystyle \frac{1}{n} \sum^{n}_{i}{\frac{y_i - u(\boldsymbol x;u(\hat{\boldsymbol \omega}^{(-1)})}{1-n^{-1}tr H(\lambda, m)}}^2$$

分母は平滑化パラメータ行列$H$のトレースを用いた。この$H$については例えるなら、前章、線形回帰でのvol.1やvol.5の$\hat{\boldsymbol \beta} = X(X^TX)^{-1}X^T \boldsymbol \beta$の変換部分である。

対数をとって

$$n\log[\frac{1}{n} \sum_{i}^{n}(y_i - u(\boldsymbol x;u(\hat{\boldsymbol \omega}^{(-1)}))^2]- 2n \log[1-n^{-1}tr H(\lambda, m)]$$

$\log(1-x)$のマクローリン展開を用いると
$$\log (1-x)= -x -\displaystyle \frac{1}{2} x^2 - ...., |x| < 1$$
であり、残差平方和/データ数nを$\hat{\sigma}^2$とする。

$$\sim n \log \hat{\sigma}^2+ 2tr H(\lambda, m)$$

と近似できる。

# 補足

基底関数の個数の決定は、クロスバリデーション抜きで行ってしまうと、

元のデータを学習データとテストデータに分割してモデルの評価をする際に、テストデータ自体で、回している際に前のサンプルで基底関数の個数を調整してしまい、オーバーフィッチング、過学習を引き起こしてしまう。

こういった事態を防ぐためにクロスバリデーションという方法が導入された。

おさらい

Step1.

$n$個の観測データの中から$i$番目のデータ$(y_i, \boldsymbol x_i)$を取りのぞいて$(n-1)$個のデータに基づいてモデルを推定し、これを$u(\boldsymbol x;u(\hat{\boldsymbol \beta}^{(-1)}))$とする。

Step2.
$(y_i, \boldsymbol x_i)$に対し$(y_i - u(\boldsymbol x_i;u(\hat{\boldsymbol \beta}^{(-1)})))^2$の値を求める.

Step3.
 
すべての$i\in (1, 2, \dots, n)$に対し、ループ実行(for文)し、

$$CV(\lambda, m)= \displaystyle \frac{1}{n} \sum_{i}^{n}(y_i - u(\boldsymbol x;u(\hat{\boldsymbol \omega}^{(-1)}))^2$$

これを観測データに基づいて推定したモデルの良さを測る基準とする。
最近のJavaScriptのナウいコードを書きたくない理由

## JavaScriptの書き方がどんどん新しくなって困惑

これは、はたしてどうなのでしょうか。

ナウいコードのうち、特にこれはとても簡単に覚えられそうなものですが

```test.js
const value=1;
let test=1;
```

どうしても、このコードを書くことができず、
結局以下のコードを書いてしまいます。

```test.js
var value=1;
```

## 理由1 2バイトも多い！

var より const のが 2バイトも多いので、転送速度にも影響するかもしれません。

それなら
```
let test=1;
```
ってのもあるかとは思いますが。。。どうも。。。

圧縮してしまえば全く影響ないものの、8bitPCをいじってたあたしにとっては、たったの2バイトのコードが増えるだけでも非常に抵抗あります。

## 愛用の Yahoo製 yuicompressorが動かない

別途 packerも通す上で、minifyするツールとしては、今でも最強だと思っています。

しかし、yuicompressorで、constもletもコードを入れると、Javaのエラーが大量に発生するのみです。

Javaで動作さえなきゃいけないのは別として、今でも多く使っているのは確かです。

きっと、きちんと管理していれば、const は不要かとは思ったりもします。


## いつから ナウいコード const に対応してるの？
いくら Internet Explorerをサポートしなくなるとしても、
IE10でもサポートしないという文面ぐらいはきちんと出したいものです。
トランスパイラにシフトチェンジした話

# トランスパイラを自作してみる試み

## トランスパイラとはなんぞや

とある言語から別の言語に変換するものっぽい。
コンパイラの一種。コンパイラの中のトランスパイラ、的な立ち位置。
トランスパイル後の言語実装は既存のトランスパイラに任せて（委託して）おけるので結構楽。

~~エンジニアの縮図みたい~~

## 使ったもの

C（だいぶ必要）

Vim(それ以外ありえない)

やる気（ほぼやる気で構成されてる）

## 実際

C++を使うのは何となく癪に触るので意地でも使わない。使うのはCだけ。

その考えがいつでも私の頭に不法滞在していて否が応でもCを使うしかなかったので労力を相当消費した。

ただその分知識はついた、と思いたい。てか思わせて欲しい。ぜひ。やってらんねえぜ、だんなぁ、、。

最初の予定ではインタプリタにする予定であったが何を血迷ったか途中で速度を求め出したため、
「さては私、それを言い訳にして言語開発から逃げ出すおつもりだな」とのよそうが脳内を通過した。

これはまずい。非常にまずい。

気づけば私は新しくフォルダを作り早くもトランスパイラ開発に着手していた。

ここで目標とやる気を見失っては春休みに何も生産せずただただ時間を消費するだけのブラックホールになりかねない。

宇宙学者としてはおそらく人類初の人工ブラックホール開発の大きな一歩になるところだが、しかし私としてはそれだけは避けたい。

大きな一歩どころか1nanoも踏み出さずやがては自分自身を吸い込んで圧倒的虚無と化してしまう。

かくして生み出されたトランスパイラだが、如何せん名前に悩む。

ここは格好良く英語で名付けてみたい気もしなくはないが、どうせ私の英語力には限界がある。

名前が英語なのに解説は全部日本語とか悲しすぎるやろ。

それならば、お気に入りのロシア語あたりで名付けたいところだが、ご時世を考えてみればおそらく偉い人からお叱りが飛んでくるだろう。

柔道の授業で受け身すらろくに取れない私としては、そんなものが飛んできてはたまったものではない。

さてどうしたものか。いっそのこと日本語にしてやるか。うん、それがいい。アニメ文化は世界共通というだろう。

なら「Myon」などはどうだろう。　、、、、！いいじゃん！かわいいじゃん！

なら言語仕様はどうしよう。

関数定義にはこだわりがある。fnを使うのだ。Rust？なんすかRustって。

トランスパイル先はCを使うから、静的型付けの方が都合がええなあ。とりあえず楽だし肩は明示的に示すようにしよか。

こんな感じか？

```
fn main(void) <- int {}
```

Rust?知らない子ですねぇ。

変数定義はどうしよか。関数定義と基本おんなじ感じの方が統一感があっていいよね。

```
let hoge:int <- "dangomushi";
```

既視感だなぁ、、、どこで見たんだろう、、理想の文法を定義してるはずなんだけどなぁ、、、

if文とかwhile文とか、制御系どうしたもんかな、、

一応文だしさいごにセミコロンあったほうが、、なんというか、、いいかんじじゃん？すっきりしない？

そう、するんですよ。

```
while (comp) { hoge };
if ( comp ) { hoge };
```

おkおk。なかなかええやん！

とりあえずここまででいいかな。え？たりない？ﾅﾝﾉｺﾄﾀﾞｶﾁｮｯﾄﾖｸﾜｶﾝﾅｲ

しょうがないじゃん！だって休みだもん！フツーに考えて集中できんよ！ｼﾃ，，ﾕﾙｼﾃ，，

[申し訳程度に、、、リポジトリ貼っときます、、、](https://github.com/pythonmaster1027/Myon "みちびいいてしんぜよう、、、")
Terraformで作ったAWSリソースの情報をWebpackで動的にJavascriptに埋め込む方法

# はじめに
Javascriptで開発をしていると困るのが、Terraformで作ったAWSリソースのURIが動的に払い出されてしまうため、開発環境とプロダクション環境で冪等にスクリプトを作れないということがあるのではなかろうか。

今回は、Webpackを使ってどんな環境でも同じコードベースで動作するように定義することをチャレンジしてみたい。

なお、今回の例ではフロントエンドのフレームワークにはVue.jsを使用している。
Vue.jsの基本的な文法や環境構築は別途前提知識として備えていることを前提としているのでご留意いただきたい。

# Javascriptの設定
さて、URIはどこに埋め込んでも良いが、main.jsなりapp.jsなりのメインに、Vue.mixinを使って埋め込むのがシンプルで良いのではなかろうか。
定数なので、グローバルとして保持しても特に問題ないだろう。
今回は、Javascriptの環境変数として保持しておきつつ、バンドル版にパックするときに置換する仕組みとする。
これにより、ローカルテスト時は環境変数をlocalhostにしてあげればモックに向けて通信することも可能になり、コードベースの冪等性も高まるはずだ。

```javascript
Vue.mixin({
  data: function () {
    return {
      APIGATEWAY_INVOKE_URL: process.env.APIGATEWAY_INVOKE_URL,
    }
  }
})
```

# Webpackの設定
Wepackでは、webpack.config.jsに以下の設定を行う。

```webpack.config.js
module.exports = {
  plugins: [
    // Vueを読み込めるようにする
    new VueLoaderPlugin(),
    // 環境変数を置換
    new webpack.DefinePlugin( (() => {
      // tfstateをJSONObjectにロードして必要な情報にアクセス可能にする
      //   ※tfstateへのパスは適宜変更する
      const jsonObject = JSON.parse(fs.readFileSync('../terraform/terraform.tfstate', 'utf8'))
      return {
        "process.env.APIGATEWAY_INVOKE_URL": JSON.stringify(jsonObject['outputs']['apigateway_invoke_url']['value'] + '/hogehoge')
      }
    })() )
  ]
};
```

# 補足: tfstateの中身
tfstateはJSON形式なので、Javascriptで読み込んで実装していくには相性が良い。
ただし、直接リソースにアクセスするのはハードルが高いため、今回は```outputs```に以下のように設定を行ってアクセシビリティを高めている。

```HCL:outputs.tf
output "apigateway_invoke_url" {
  value = aws_api_gateway_stage.prod.invoke_url
}
```

こうすることで、tfstate上では以下のように定義されるようになる。

```json:terraform.tfstate
{
  "version": 4,
  "terraform_version": "0.14.5",
  "serial": 559,
  "lineage": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "outputs": {
    "apigateway_invoke_url": {
      "value": "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod",
      "type": "string"
    }
  },
  (以下略)
}
```

リモートステートを使用している場合は、```terraform output -json```することで同様の出力を得ることができる。

```bash
$ terraform output -json
{
  "apigateway_invoke_url": {
    "sensitive": false,
    "type": "string",
    "value": "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod"
  }
}
```

# WebpackによりバンドルされたJavascript
これで、```npm run webpack```すれば、以下のように変換される。
どんな環境でも同じコードベースからバンドル版のJavascriptを生成できるようになった！

```javascript
vue__WEBPACK_IMPORTED_MODULE_1__["default"].mixin({
  data: function data() {
    return {
      APIGATEWAY_INVOKE_URL: "https://urhgcdv4mi.execute-api.ap-northeast-1.amazonaws.com/prod/hogehoge"
    };
  }
});
```
【Unity】アニメーションに移行するのが遅い

<h2>はじめに</h2>
<p>どうも、あおいちです。</p>
<p>今回は<b>「アニメーションに移行するまでに時間がかかる！なんで？」</b>と思った人向けに、はUnityのAnimatorにおいて設定したアニメーションがすぐに移行しない理由を簡潔に解説していきたいと思います。本記事を最後まで読んでいただければ幸いです。</p>

<h2>症状と原因</h2>

<p>結論から言うと、下記の画像にもある<b>Has Exit Time</b>にチェックがついていることが原因だと考えられます。※こちらはProjectから使用しているアニメーターを開くとInspectorの画面がこのようになります。</p>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600193/ad02e297-5529-a83f-902c-a39d6f3140b2.png" width="30%" height="30%">

<p>アニメーションの遷移において、"Exit Time"という遷移時間が存在し、これによってアニメーションが遷移までのフレーム数を決定することができます。今回は、アニメーションを瞬時に設定して欲しいことから、その箇所のチェックさえはずしてもらえれば直るはずです。</p>


<h2>参考</h2>

<a href=""https://docs.unity3d.com/ja/2018.4/Manual/class-Transition.html>アニメーション遷移 - Unity マニュアル</a>
<p>
スマートウォッチアプリの開発#2

前回の続き・・・
「iphoneでアプリ内のボタンを押すとスマートウォッチが振動するアプリ」をアンドロイドスタジオを使って、開発することに決定した。

今回の目的
android wearアプリ開発における、デバイスからwear OSの通知の送受信を参考通りに進める。（参考文献は記事下に記載）

結論
参考文献の内容が2015出版で、現在のandroid studioのverではbuildできないため、そのデバッグ作業を進めたが、途中で挫折。

結果
android studioの基本セッティング。
上記結論のどうやらAPI、SDK通信のverを端末のverに合わせねばならず、一つ一つコードを書き換えることに。
API設定が上手く行かず、五里霧中になり、ひとまず退散。
またandroid設計するにあたり、Javaの基本的なコードを抑えておかなければ、前進できないので勉強する必要がありハードルが高そう。（時間考えてできるかの検討は明日の宿題とする。）

参考
android wear入門 アプリ開発入門
https://www.amazon.co.jp/Android-Wear%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-Software-Design-plus/dp/4774177490
pandasを用いて祝日を取得 

# はじめに
年次作業などでシステムのプロパティファイル（祝日の定義）などを更新するとき、祝日を簡単に取得できたらいいなと思いました。pandasを用いると簡単に取得できたので紹介します。
# 環境
* python 3.7.4 
* Windows10
# 取得データ
https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html

# データ取得
ダウンロード後、カラム名を変更。
```py
import pandas as pd

url = "https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv"
df = pd.read_csv(url, encoding="SHIFT-JIS")
df = df.rename(
    columns={
        "国民の祝日・休日月日": "national_holiday_ymd",
        "国民の祝日・休日名称": "national_holiday_name",
    }
)
```
# データ整形
```py
df["national_holiday_ymd"] = pd.to_datetime(
    df["national_holiday_ymd"], format="%Y-%m-%d"
)
# year(年度)カラムを追加
df.loc[df["national_holiday_ymd"].dt.month >= 4, "year"] = df[
    "national_holiday_ymd"
].dt.year
df.loc[df["national_holiday_ymd"].dt.month < 4, "year"] = (
    df["national_holiday_ymd"].dt.year - 1
)

# yearカラムをfloat型からint型に変換
df["year"] = df["year"].astype(int)
# stringに変換
df["month"] = df["national_holiday_ymd"].dt.month.astype(str)
df["day"] = df["national_holiday_ymd"].dt.day.astype(str)
# m/dの形にする
df["date"] = df["month"].str.cat(df["day"], sep="/")
```
![df_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1628462/0997e235-2109-b2e2-2b22-c4024e189110.png)

# 2022年度のデータに絞り日付を出力
```py
# 2022年度を抽出
# 最後のデータは','は不要なので分岐させています。
df_tmp = df.query("year == 2022").reset_index()
# 日付のみを1行で出力
for index, item in df_tmp.iterrows():
    if index == len(df_tmp["date"]) - 1:
        print("'" + item["date"] + "'", end="")
    else:
        print("'" + item["date"] + "'" + ",", end="")
```
出力結果は下記。

```
'4/29','5/3','5/4','5/5','7/18','8/11','9/19','9/23','10/10','11/3','11/23','1/1','1/2','1/9','2/11','2/23','3/21
```

# 参考ページ
https://qiita.com/toshikawa/items/2d535906b42b9332b743
https://tamiz-blog.com/programming/pandas/pandas20210221/
40代おっさんPythonでWeb APIを叩いてみる

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## APIを叩く上で必要な情報

### APIに接続するための情報

・API登録のタイミングで入手
・サービスに接続するためのURLであるAPIエンドポイント
・接続に必要なID的要素、APIキーが必要

### APIに送信する情報

・基本的には各APIのドキュメントに細かく記載
HTTP：どのHTTPメソッドを使用するか（主にPOSTかGETを使用）
header:ヘッダーにはデータの種類や、APIキーなどの認証情報を記載
body:JSON形式で送受信したい情報（データ）を記載

## JSONを理解する

リクエストの送信・レスポンスにはJSONフォーマットの理解が必要

### JSONとは

JavaScript Object Notationの略
JavaScriptのオブジェクトの書き方を元にしたデータフォーマット
XMLなどと同様のテキストベースのデータフォーマット

#### XML

タグと呼ばれるものを用いてデータ構造を表現
開始タグと終了タグが対になった表記方法

```xml
<?xml version="2.0" encoding="utf-8"?>
<data>
 <item>
   <id>1</id>
   <name>lmanyu</name>
 </item>
 <item>
   <id>2</id>
   <name>lmanishi</name>
 </item>
</data>
```

XMLは直感的に理解しにくい点がある

#### JSON

```json
[
 {"id":"1","name":"lmanyu"},
 {"id":"2","name":"lmanishi"}
]
```

同じデータを扱っているにも関わらず情報量に大きな違いが出る

### JSONの書き方

JSONは{}の中にキーとバリューをコロンで区切って記述する

```json
{
 "id":"1",
 "name":"lmanyu"
}
```

キーは必ずダブルクォーテーションで囲む必要があり、シングルクォーテーションだとエラーになってしまう

## HTTPメソッド

クライアント（API使用者/ユーザー）が行いたい処理をサーバー（API側）に伝えるという役割

### GET

WebページやAPIからのデータ取得
cssファイルやjavascriptファイルと言ったデータ取得

### POST

フォームからデータを送信
アカウントの新規作成
新規データを作成

### PUT

既存データの編集
（アカウントやツイート情報、SNS上でのコメントなどを編集）

### DELETE

データの削除
（アカウントやブログ記事、その他様々なデータを削除する）

## Pythonを用いてAPIを使ってみる

今回はJSONPlaceholderを使用
その中のpostsを使う

```python
!pip3 install requests
```

リクエストを送るのに必要なライブラリ
インポート

```python
import requests
```

エンドポイントを変数urlに格納

```python
url = 'https://jsonplaceholder.typicode.com/posts/'
```

HTTPメソッドのGETを使用
requestsを使用してgetの中に変数urlを入れる、そして変数resに格納

```python
res = requests.get(url)
```

res.status_codeを入れて叩くと
200
が返ってきたら成功です

res.json()と叩くとレスポンスの中身をJSON形式で取得できます。

res.json()[:5]
これで前5個見れる

とりあえず、最初のデータを変数datumに格納

```python
datum = res.json()[0]
```

欲しい情報だけをとる
[]のなかに記入
とりあえず、titleを取ってくる

```python
datum['title']
```

特定の情報を取ってくる
とりあえず、ID10番目の情報を取ってくる

```python
url = 'https://jsonplaceholder.typicode.com/posts/'
body = {
    'id': 10
}

res = requests.get(url, body)
res.json()
```

### 参考資料

<https://www.udemy.com/course/python-web-api/learn/lecture/25073250#overview>
Reactの学習記録①

### `create-react-app`で生成されるフォルダについて
- src
→開発用ファイルが格納される。ReactコンポーネントのJSXファイルなどはここに置く
- public
→静的ファイルが格納される（htmlや画像ファイルなど）
- build
→本番用ファイルが格納される（`npm run build`で生成される）

### コンポーネントとは
- 見た目と機能を持つUI部品
- コンポーネントを組み合わせてページをつくる
- Class ComponentとFunctional Componetの大きく2種類のコンポーネントに分かれるが
最近ではClass Componentはほとんど使われない

### Functional Componentの特徴
- ES6のアロー関数で記述する
- 基本的にはstateを持たない
- propsを引数に受け取る
- JSXをreturnする


```react
// Functional Componentの例
const Button = (props) => {
  return <button>Say, {props.hello}</button>;
};

export default Button;
```

### コンポーネントを使用するメリットは何か
- 再利用するため
→同じ記述を何度もすることを防ぐことができる
- コードの見通しをよくするため
→ファイルを細かく分割することでコードが読みやすくなる
- 変更に強くする
→修正する際は、元となる部分の１箇所だけでOK
[Rails]deviseのuser_signed_in?メソッドが常にfalseを返す不具合への対処法。

Railsで転職活動用のポートフォリオ作成中です。
deviseの`user_signed_in?`メソッドが正常に動作しない不具合が発生しました。


## 不具合詳細
確かにログインできているのに、`user_signed_in?`が常に`false`を返す。


```bash:console
...
     8:       <% binding.pry %>
 =>  9:     <% if user_signed_in? %>
    10:       <p>ユーザー詳細です。</p>
    11:       <p><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></p>
    12:     <% end %>
...
$ user_signed_in?
=> false
```

## 前提事項
・macOS Monterey v12.1
・ruby v3.0.3
・Rails v6.1.4.4
・devise 4.8.1

その他
・自作のユーザー認証機能のdeviseへの置き換え途中に発生したエラー
・自作の認証機能は、ほぼRailsチュートリアルのコピー

 ## 原因
自作の`current_user`メソッドが`sessions_helper`に残っており、その実行結果（nil）を`user_signed_in?`メソッドが参照してfalseを返していた。

参考（英語）：

https://stackoverflow.com/questions/12241322/user-signed-in-always-returns-false

## 対策
以下の`current_user`メソッドを削除（コメントアウト）する。
（Railsチュートリアルを参考にしてきた場合は、おそらくsessions_helperに記載がある。）
### before
```ruby:app/helpers/sessions_helper.rb
module SessionsHelper
  ...
  # 記憶トークンcookieに対応するユーザーを返す
  def current_user
    if (user_id = session[:user_id])
      @current_user ||= User.find_by(id: user_id)
    elsif (user_id = cookies.signed[:user_id])
      user = User.find_by(id: user_id)
      if user&.authenticated?(:remember, cookies[:remember_token])
        log_in user
        @current_user = user
      end
    end
  end
  ...
end
```
### after
```ruby:app/helpers/sessions_helper.rb
module SessionsHelper
  ...
  # 記憶トークンcookieに対応するユーザーを返す
  # def current_user
  #   if (user_id = session[:user_id])
  #     @current_user ||= User.find_by(id: user_id)
  #   elsif (user_id = cookies.signed[:user_id])
  #     user = User.find_by(id: user_id)
  #     if user&.authenticated?(:remember, cookies[:remember_token])
  #       log_in user
  #       @current_user = user
  #     end
  #   end
  # end
  ...
end
```

## 考察
なぜ`current_user`のコメントアウトのみで`user_signed_in`の不具合も改善されたのか。

特にdeviseメソッドの中身を調べたわけではないので予想に過ぎませんが、diviseの`user_signed_in`メソッドは`current_user`メソッドの実行結果を参照しているのでなないでしょうか。
今回発生した不具合に関係する処理の中に`current_user`はありませんでした。しかし、自作の`current_user`が実行され、中身を見てみたところ`nil`が入っていました。

```bash:console
...
    13: def current_user
    14:   if (user_id = session[:user_id])
    15:     @current_user ||= User.find_by(id: user_id)
    16:   elsif (user_id = cookies.signed[:user_id])
    17:     user = User.find_by(id: user_id)
    18:     if user&.authenticated?(:remember, cookies[:remember_token])
    19:       log_in user
    20:       @current_user = user
    21:     end
    22:   end
    23:   binding.pry
 => 24: end

[1] pry(#<UsersController>)> current_user
=> nil
```
`user_signed_in`メソッドが、「`current_user`の中身が`nil`ならユーザーはログインしていないだろう」と判断していた説。

## まとめ
同じ名前のメソッドには要注意。
リモートリポジトリにプッシュするときにusernameとpasswordが求められるときの対処法

## 概要
リモートリポジトリにプッシュするときにusernameとpasswordが求められるときがある。
これがまた、めんどい...

```bash:terminal
Username for 'https://github.com': Username
Password for 'https://Username@github.com':
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/Username/Repo_name.git/'
```

## 解決法
.git/configファイル内を確認すると以下のように書かれている。(2022/04/03時点)

```bash:terminal
hoge$ vi .git/config

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
[remote "origin"]
        url = https://github.com/Username/Repo_name.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
        remote = origin
        merge = refs/heads/main
```

[core]内のurl内を以下のように変更する。

```
url = git@github.com:Username/Repo_name.git
```

再度pushしてみるとusernameやpasswordを聞かれずにpushできるようになった。

## 参考
https://qiita.com/sayama0402/items/670b6b650ebdd8680a0b
AzCopy のエラーハンドリング

[以前の記事](https://qiita.com/trtrbohz/items/23324a9376b25ae1324d "Azure Blob Storage へのフォルダ・ファイルアップロード")にて、Powershell スクリプトとAzCopyを組み合わせて Azure Blob Storage へファイルやフォルダをアップロードするスクリプトを紹介しました。
この[AzCopy](https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-azcopy-v10  "AzCopy を使ってみる")ってすごく簡単で動作が軽く秀逸なツールだと思っています。
ですが、AzCopyって非同期的な動作でログを Azure Blobstorage へ転送するので、AzCopyでエラーが発生した場合の対応というのが[こちら](https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-azcopy-configure "AzCopy でログとプラン ファイルを使用してエラーの検出とジョブの再開を行う")の記事のように「ログとプラン ファイルを使用してエラーの検出とジョブの再開を行う」対処しようとするととてつもなく大変になってしまいます。

そこで対応として、[Start-Process]("https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-7.2")コマンドレットと組み合わせて同期的な動作のもとエラーハンドリングをしてみました。

そのスニペットは以下です。（環境としては、AzCopy.exe をおいてあるフォルダの中で実行しています。)
```
$proc = Start-Process -FilePath ".\azcopy.exe" -ArgumentList "copy","C:¥temp¥Logs","https://.....%3D(Shared Access Signagure:SAS)","--recursive=true" -PassThru -Wait
if($proc.ExitCode -ne 0)  # アップロード失敗  アップロード用構成フォルダを削除
{　　　　　# エラー発生
    Write-Host "error:" $proc.ExitCode
    # 何らかのエラー発生したので、その対策を記載
}
else
{    # エラーなし
     Write-Host "success:" $proc.ExitCode
     # AzCopy 成功時にすることを記載
}
```

ここで、Start-Process の使い方は起動したいプロセスを -FilePath 引数として記載し、そのプロセスの引数を -ArgumentList 引数にカンマ区切りで記載します。
また、Start-Process の引数として「-PassThru」を付けました。詳しくは[こちら](https://tech.guitarrapc.com/entry/2013/01/24/200115)
のページで解説してくれています。AzCopy の成功時に何も返却オブジェクトがなく Start-Process 成否判定にうまく引っかからなかった。そのため、何らかのオブジェクトを Start-Proceee から得られるように「-PassThru」を付けた次第です。
あと、「-Wait」。これをつけなければ AzCopy の完了を待たずエラーハンドリングができません。なので、AzCopy の実行終了を待つために付与しております。

以上のコードで AzCopy のエラーハンドリングが行えるようになりました！
【初心者応援】エンジニアにとって重要な2つのスキルとは？

# はじめに

[新人プログラマ応援 - みんなで新人を育てよう！](https://qiita.com/official-events/3f21c92121aa125807b4)
ということで、今月から社会人となり、エンジニアになる方も多いのではないでしょうか？
今月は上記イベントに合わせて初心者応援をキーワードとして記事を書いていこうと思います。

今回は初心者応援第２弾、新人エンジニアに必ず伝えている重要な２つのスキルに関して記事にしていこうと思います。

# 重要なスキルその１：検索技術

まず1つ目にお伝えする重要な技術は検索技術です。
一見エンジニアのスキルと関係なく感じ、疑問に持たれる方もいらっしゃるかもしれませんが、日々業務を遂行していく上で大変重要なスキルです。

普段何気なく日常の中で検索し、情報を得ていると思いますが、エンジニアの場合も同様に検索から情報を得ていますよね。
ただし、普段とはまた違った検索技術が必要です。
不具合を例に出すとわかりやすいかもしれません。

例えば、ログを元に不具合の原因を追うとします。
極端ですが、ログを全部検索欄に貼り付けて検索したら何も出ない、なんて事になりますよね。
これをログの重要な要素だけを切り取り、以下のような形で検索ワードに並べてみると類似した情報が出てきます。

例：kotlin XXXXException XXXX など

**つまり検索ワードをできる限り最適化し、適切な内容で検索する事で欲しい情報になるべく目を向ける事ができる状況を作る**、これがとても重要になります。

初心者の方であれば、知見が少ない事が理由で正しい情報を抜粋する事ができず、検索から情報を得るまでに時間がかかるなんて事がよく起こります。
そんな中で少しでもみるべき情報を検索時に絞る事ができれば、迷ったとしても、失敗が少なくなるはずです。

クオリティの高い情報を吸い上げる事ができるようになれば、スムーズに検証に移る事ができるようになるので、気持ち的にも余裕ができます。

検索技術は経験値に基づく要素が大きいですが、初心者の方であればあるほど、わからない事に溢れているはずです。
その点において、検索すべき事項というのはたくさんあるはずなので、最初のうちは余す事なく調べ、ただ調べるだけではなく、検索方法も毎度工夫する事で少しずつ検索技術を向上させる事ができるかと思います。
もちろん、周りの先輩エンジニアに検索方法を聞いてみたりするのも、良い方法だと思います。

是非開発の中で検索にも意識を向けて業務と向き合ってみる事をオススメします。

# 重要なスキルその２：検証技術

2つ目にお伝えする重要な技術は検証技術になります。
エンジニアであれば、学習中にも当たり前のように行っている検証作業ですが、改めて日々の業務フローで考えてみると重要だという事がよくわかります。

例えば、不具合修正を行うとします。
まず報告を受けた事象を再現させる為、検証しますよね。
その後、検証した結果得た情報を使用して検索します。
検索した結果、吸い上げた情報を使用して再度検証します。

これはエンジニアであれば当然の事を述べていますが、**基本的な作業のルーティンは検証→検索→検証と、これを繰り返しているので、業務の大半を占めている検証技術は遂行している業務のクオリティに直結する重要な要素**だという事です。

ただし、上記作業を機械的に述べるのは簡単ですが、実際の作業では検証する上で現状のコードを深く理解する必要があったり、ブレイクポイントなどのシステム的検証方法を理解する必要があると思います。
システム的検証方法であれば覚えれば良いだけですが、左記以外で初心者の方がよりクオリティの高い検証を行う為にはどうしたら良いのでしょうか。

私がよくお伝えする方法はとてもシンプルで、**とにかくコードを読む**という事です。

まず検証時において重要な要素を担っているのは、コードのリーディング力です。
初めて参画したプロジェクト、初心者の方であれば、想像しているよりも難しく感じる事がほとんどです。

そんな中でなるべく早く適応し成果を上げていくには、リーディング力から参照しているコードの動きがイメージができる事が重要です。

その点において、普段からコードを読み、まずは目を慣らすというのはとても良いトレーニングになります。
GitHubなどで公開しているプロジェクトのコードを読んでみたり、言語のリファレンスを覗いてみても良いかもしれません。

最初のうちは理解できていなかったコードも、少しずつこんな事しているのかな？、とイメージできるようになり、リーディング力が高まるはずです。

是非本を読むような感覚で、色々なコードを読んでみる事をオススメします。

# さいごに

私は新人の方には必ず、検索技術と検証技術は重要なスキルとお話していますが、このスキルは日々業務を進めていく上で切り離すことのできない重要な技術です。
もちろんエンジニア間のコミュニケーションも重要ですが、最終的にそのタスクをこなすのは自分なので、是非言語の勉強と合わせて上記スキルも高めてもらえると良いかと思います。
AtCoder ABC246で不正解になった問題を解いてみた

# 概要
AtCoder ABCに参加して私が不正解になった問題を再度解いてみる。
最適な解法はAtCoderサイトの解説をご確認いただきたいが、自分なりに**解いていく過程を書いていきたい**と思う。
今回はABC246。以下を自分なりに解いてみた。

:::note info
* 不正解問題：**D問題**
:::

![ABC246.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603145/c7ac1d7b-5e55-8366-0c87-f494126fe5e7.jpeg)

# ABC246 D問題：2-variable Function
[問題文リンク](https://atcoder.jp/contests/abc246/tasks/abc246_d)
下記を満たす最小のXを求める問題。
```math
X=a^3+a^2b+ab^2+b^3 (整数a\geqq 0,整数b\geqq 0)\\
0\leqq N\leqq X\leqq 10^{18}
```

### 解く過程での私の思考
1. 変数a,bは非負整数なので、`a1<a2`だと`X(a1,b)<X(a2,b)`が成り立つ。bも同様。
また、`X(a,b)=X(b,a)`も成り立つ。
1. a,bの範囲として考えておく必要がある上限は高々Nの三乗根であろう。
1. 以下のように後は最小値を追い込んでいけばよいはず。
    1. Nの三乗根以上の最小の整数をb0として、X(0,b0)を候補値minXとする。
    1. bをデクリメントしていきmin(minX,X(a,b))でminXを更新していき、X(a,b)がN以下になるまで進める。
    1. aをインクリメントする。
    1. 2./3.を繰り返し、a=bになれば終了。

下図で赤はN以上の(a,b)組み合わせ、黄はN未満、灰色は結果探索しないことになる組み合わせを示す。
![ABC246D0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603145/e69d70db-a097-e56e-e750-429b907e93e8.png)

私が正解に辿り着けたコードは以下。
```
int main() {
  int64_t N;
  cin >> N;
 
  // X >= N
  // X = a^3 + a^2 * b + a*b^2 + b^3
  double root3N = pow((double)N,(double)1/(double)3) ;
  int64_t maxB = (int64_t)root3N + 1;
 
  int64_t A = 0 ;
  int64_t B = maxB ;
  int64_t minX = (A+B) * (A*A + B*B) ;
  int64_t currX ;
  bool b_decr = true;
  while ( A <= B ){
    if (b_decr) B--;
    else A++ ;
    currX = (A+B) * (A*A + B*B) ;
    if (currX<N){
      b_decr = false;
      continue;
    }
    b_decr = true;
    minX = min(minX, currX);
  }
  cout << minX << endl;
  return 0;
}
```
Splunk: Splunk入門


 Splunk を使用するための基本的な情報をまとめました。
 Splunk を GUI から操作しデータの検索・集計を行うことを想定した記事で、環境構築向けではありません。

### 基本編

* [そもそもSplunkって何? (2022/04/03)](https://qiita.com/frozencatpisces/items/59703f57ce88ec936255)

### SPL編

* [SPL文の基本 (2022/04/10)](https://qiita.com/frozencatpisces/items/a395d8721977d14bd6a2)

* [よく使用するコマンド11選 (2022/04/17)](https://qiita.com/frozencatpisces/items/7e35fd70b45fad974277)

* [よく使用する統計関数11選 (2022/04/24)](https://qiita.com/frozencatpisces/items/360b4a38212fe1876dbc)

* [よく使用する評価関数11選 (2022/05/01)](https://qiita.com/frozencatpisces/items/70b39a08cf9e9a3d140d)

* [演算子一覧 (2022/05/08)](https://qiita.com/frozencatpisces/items/1ccd4344b4953f049526)

* [SPL結果の表示形式 (2022/05/15)](https://qiita.com/frozencatpisces/items/77f11bcc93eca847239c)

### グラフ編

* [折れ線グラフ・積み上げ折れ線グラフ (2022/05/22)](https://qiita.com/frozencatpisces/items/fb749671774315f4231d)

* [棒グラフ・積み上げ棒グラフ (2022/05/29)](https://qiita.com/frozencatpisces/items/9e59aa7b3df67d2c7399)

* [円グラフ (2022/06/05)](https://qiita.com/frozencatpisces/items/90ac292508ac500d04cd)

* [単一値グラフ (2022/06/12)](https://qiita.com/frozencatpisces/items/51e5ecab28510e7809fa)

### ダッシュボード編

* [ダッシュボードの基本 (2022/06/19)](https://qiita.com/frozencatpisces/items/70f5bdf3331ea58e50f1)

* [ダッシュボードの入力 (2022/06/26)](https://qiita.com/frozencatpisces/items/5e6f42b7e8653ba0fd18)
主キーの追加方法

# 主キーの追加方法
`ALTER TABLE test_table ADD CONSTRAINT [追加するプライマリキーの名前]
 PRIMARY KEY (ids,from_date)`

https://www.ipentec.com/document/sql-server-add-primary-key-column-of-table

https://docs.microsoft.com/ja-jp/sql/relational-databases/tables/create-primary-keys?view=sql-server-ver15

https://lightgauge.net/database/sqlserver/743/
元組み込みC++エンジニアがWebアプリを作ってみる - とりあえず動かしてみる

※親ページは[コチラ](https://qiita.com/dashi-no-ajiwai/items/c1e776a17e0c1e6af40b)

# やること
とりあえず、バックエンドのルーターを作って動かしてみます。
ブラウザでURL(今はローカルなので`localhost`)を指定して、データが取得できることを確認します。

# 下準備
だいたいターミナル操作です。
## ディレクトリ構成
```
$ cd ~
$ # 作成するアプリのもろもろを配置するディレクトリ
$ mkdir first_app && cd first_app
$ # ページのルーターを配置するディレクトリ
$ mkdir first_app_router && cd first_app_router
```
## インストール
- [Go](https://go.dev/)
Macなら[Homebrew](https://brew.sh/index_ja)が入っていれば楽ですね。
現時点で`1.18`が最新です。
```
$ brew install go
$ go version
go version go1.18 darwin/amd64
```
- [VSCode](https://code.visualstudio.com/)
    - 拡張機能[Go](https://marketplace.visualstudio.com/items?itemName=golang.Go)

## モジュール管理ツールModulesの初期化
依存モジュールを管理するため、Goに組み込まれているモジュール管理ツールModulesを初期化します。

https://qiita.com/uchiko/items/64fb3020dd64cf211d4e

```
$ # とりあえずGitHubなどで公開しないので、モジュール名はよしなに
$ go mod init first_app_router
```
実行すると、`go.mod`が生成されるはずです。
```
$ cat go.mod 
module first_app_router

go 1.18
```

# 作ってみましょう
※以下、引き続き`~/first_app/first_app_router`で作業します。

## 処理メイン部分`main.go`を作成
```main.go
package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

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

	engine.GET("/", func (c *gin.Context) {
		c.JSON(http.StatusOK, gin.H {
			"message": "Hello, my first app!",
		})
	})

	engine.Run(":8080")
}
```
**えっ？これだけで動くの？** と思うじゃないですか。**動きます。**
このソースコードでやっているのは、ブラウザからアクセスするとJSON形式で`{"message":"Hello, my first app!"}`を表示するだけですが、少なくともこれだけで自分の作ったものが動くことを確認できます。
(本来はちゃんとHTMLを出したいところですが、テンプレートの準備などが必要なため、JSONにしています)

## ビルド(失敗します)
ビルドして、実行バイナリを生成します。
```
$ go build
main.go:5:2: no required module provides package github.com/gin-gonic/gin; to add it:
        go get github.com/gin-gonic/gin
```
「使用するモジュールがありません」ですね。
`main.go`で`import`しているGinが見つからないためです。
エラーメッセージに従って、`get`してみましょう。

## モジュールを`get`
```
$ go get github.com/gin-gonic/gin
```
追加モジュールが`get`できましたね。

## 今度こそビルド
ビルドして、実行バイナリを生成します。
```
$ go build
```
何もエラーが出ていなければ、ビルド成功です！おめでとうございます🎉
エラーが出ていれば、エラーメッセージを読んだり検索かけてみて対処しましょう。
(こちらの環境では`golang.org/x/sys`関連のエラーが発生しており、`go get -u golang.org/x/sys`が必要でした)

ビルドできれば、実行バイナリ`first_app_router`が生成されています。

# 動かしてみましょう
## 起動しないでブラウザからアクセス
まずはお手元のブラウザのURLを入れるところに`localhost:8080`と入れ、アクセスしてみましょう。
表示できませんね？それでOKです。
何か表示されてしまうようなら、そのアプリを止めるか、ソースコードのポート番号(`engine.Run(":8080")`の`":8080"`)を適当なものに変えましょう。

## 起動
ターミナルからバイナリを起動します。
```
$ ./first_app_router
...(何か出る)..
```

## 起動してブラウザからアクセス
ブラウザでさっき表示できなかったページを再読み込みしてみましょう。
![スクリーンショット 2022-04-03 20.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611038/a7907d91-35c5-225e-4f2c-b7a332540654.png)
このような文字列が表示されましたか？おめでとうございます🎉
もしも自分で作成したものが表示されているのか不安なら、ソースコードを変えてみて再ビルドして同じようにやってみましょう。

## 実行を止めてブラウザからアクセス
ターミナルで`Ctrl + C`で実行を止め、ブラウザで再読み込みしてみましょう。
表示できませんね？実行を止めればもちろん表示できなくなります。


# いかがでしたか
ソースコード20行くらいだけで、もうバックエンドっぽいものができちゃいました。
GoとGinのおかげですね！

ただし、まだページらしいページは表示できていませんし、デバッグもできていません。
以降はこれらができる方法を紹介します。
OCIのAutonomous Data Warehouseを作成しよう

## 手順
１．Autonomous Data Warehouseとは
２．Autonomous Data Warehouseを作成

## １．Autonomous Data Warehouseとは

https://www.oracle.com/jp/autonomous-database/autonomous-data-warehouse/

https://oracle-japan.github.io/ocitutorials/database/adb101-provisioning/

## ２．Autonomous Data Warehouseを作成
① 「ナビゲーションメニュー」→「Oracle Database」→「Autonomous Data Warehouse」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/77cf4aa7-4edb-cc7d-ebba-8b7909071112.png)
② どのコンパートメントに作成するかを選択し、「Autonomous Databaseの作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/546d065a-440b-c685-d004-21c3351192bb.png)
③

:::note info
コンパートメント：springAnalytics
表示名：springADW
データベース名：springADW
ワークロード・タイプの選択：データ・ウェアハウス
デプロイメント・タイプの選択：共有インフラストラクチャ
Always Free：off
データベース・バージョンの選択：19c
OCPU数：1
OCPUの自動スケーリング：チェック
ストレージ(TB)：1
ストレージの自動スケーリング：チェック
パスワード：Welcome12345#
パスワードの確認：Welcome12345#
ネットワーク・アクセスの選択：すべての場所からのセキュア・アクセス
ライセンス・タイプの選択：ライセンス込み
:::

④ 「Autonomous Databaseの作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/df353688-25b0-963d-b436-073d1d2b30fa.png)
⑤ Autonomous Data Warehouseのインスタンス作成完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/9eee3e4a-eef5-d285-1103-0a81c4523965.png)
[Kotlin]メンバ変数に対する分解宣言時のエラー

# 分解宣言
Kotlinでは、分解宣言という仕組みがあるが、代入先はローカル変数のみが可能で、
メンバ変数の場合、以下のエラーが発生する。

```
Destructuring declarations are only allowed for local variables/values
```

## 動作環境
+ Kotlin 1.6.10

## エラーが発生する例
```
data class Data(
	val data1: String,
	val data2: String,
	val data3: String
)

class Test {
    // メンバ変数のため分解宣言不可
    val (test1, test2, test3) = Data("string1", "string2", "string3")
    
    fun print() {
        print("${test1}, ${test2}, ${test3}")
    } 
}

fun main() {
    val test = Test()
    test.print()
}
```

## エラーが発生しない例
```
data class Data(
	val data1: String,
	val data2: String,
	val data3: String
)

class Test {
    fun print() {
        // ローカル変数のため分解宣言可能
        val (test1, test2, test3) = Data("string1", "string2", "string3")
        print("${test1}, ${test2}, ${test3}")
    }
}

fun main() {
    val test = Test()
    test.print()
}
```

discuss.kotlinlang.orgにはトピックとして挙がっているが、特に回答はなく、不可である理由は不明。
（日本語での情報も特にないので、もしかすると当たり前の常識なのかもしれない？）

# 参考
https://discuss.kotlinlang.org/t/why-are-destructuring-declarations-only-allowed-for-local-variables-values/19200
findViewById vs viewBinding

# findViewById vs viewBinding

Kotlin での Android アプリ開発勉強中のみやジックです。
現在は Google の提供している Android Basics in Kotlin を進めています。
[Unit 2:Layouts の Pathway1](https://developer.android.com/codelabs/basic-android-kotlin-training-tip-calculator?hl=ja&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fandroid-basics-kotlin-unit-2-pathway-1%3Fhl%3Dja%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fbasic-android-kotlin-training-tip-calculator#2)で viewBinding が出てきて、「ん?」ってなったので頭の中を整理するためにこの記事を書きます。

## viewBinding とはなんぞ

> コードが View に対するメソッドを呼び出したり、その属性にアクセスしたりする前に、コードで Button や TextView などの View への参照を調べる必要があります。Android フレームワークには、findViewById() というメソッドが用意されており、View の ID を指定してその参照を返すという、まさにここで必要な操作を行えます。このアプローチは効果的ですが、アプリにビューを追加すると UI が複雑になるため、findViewById() の使用が難しくなる可能性があります。

まあ、View をコードから参照するときに便利にやってくれるやつ。

これまでは findViewById()を使って参照してたけど、それより楽になるやで~って書いてある。

ちなみに Bind って聞くとなんか縛り付けるイメージあるけど、関連づけや参照のような意味っぽい

## findById より本当に楽なん？

実際にやってみた。
まずは findById での参照を[Unit 1:KotlinBasics の Pathway4](https://developer.android.com/courses/pathways/android-basics-kotlin-four?hl=ja#codelab-https://developer.android.com/codelabs/basic-android-kotlin-training-create-dice-roller-app-with-button)を参考にやってみる。

まず、viewsと呼ばれる部品をactivity_main.xmlに配置します。今回はTextViewとButtonの二つを配置しました。


<img src="https://user-images.githubusercontent.com/62228968/161419557-0da848c7-2f06-4e9a-b975-1761d3b581bb.jpg" width="500">

MainActivity.ktからfindByIdでTextViewとButtonの参照をして、Buttonの押下でtextを変更できるようにする。

```kotlin:MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val rollButton: Button = findViewById(R.id.button)
        val textView: TextView = findViewById(R.id.textView)
        rollButton.setOnClickListener {
            textView.text = "changed"
        }
    }
}
```

こんな感じになる。それぞれのviewsごとにfindViewByIdを呼ぶことになる。

次にviewBindingで書き直してみる。

```kotlin:MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.button.setOnClickListener {
            binding.textView.text = "changed"
        }
    }
}
```

※ viewBindingを使うときはbuild.gradleで設定する必要があるので注意

build.gradle内のandroidブロック内に下記を追記して、SyncNowをクリック

```
    buildFeatures {
        viewBinding = true
    }
```

これでviewBindingを用いて同じ挙動の実装ができた。
MainActivityクラス内では、viewの数だけfindByIdを呼ぶ必要が無くなった。viewが増えれば増えるほどviewBindingの利点は大きくなりそう。

今回書いたコードのリポジトリ

https://github.com/miyaji555/findById_VS_viewBinding
VCNウィザードの起動を利用して、OCI上で簡単にVCNを作成しよう

### 1.仮想クラウド・ネットワークへアクセス
「ナビゲーション・メニュー」→「ネットワーキング」→「仮想クラウド・ネットワーク」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/55ff9750-5418-5a81-809b-cee59d0147dd.png)

### 2.VCNウィザードの起動
① どのコンパートメントに作成するかを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/2f91f346-54eb-5b4b-8a94-7d3eb8f1f958.png)

② 「VCNウィザードの起動」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/7ebd278c-4b60-966a-11a1-abab4a875517.png)

③ 「インターネット接続性を持つVCNの作成」を選択し、「VCNウィザードの起動」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/576a967d-5653-53ba-23ba-9d49229b1b2b.png)


### 3.VCN構成を入力
①
VCN名：springvcn
コンパートメント：springAnalytics
VCN CIDRブロック：10.0.0.0/16
パブリック・サブネットCIDRブロック：10.0.0.0/24
プライベート・サブネットCIDRブロック：10.0.1.0/24
DNS解決：チェック
② 「次」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/3b1cf631-8e81-4385-fc1e-1502eeef1007.png)

③ 作成をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/588234fc-ffec-fece-81c4-57adab73694d.png)

### 4.仮想クラウド・ネットワークの表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/b98c42da-7627-6f94-f882-235394e98584.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562390/4ad01460-7aa0-62b1-f117-74c57bf7f630.png)

## 参考サイト
https://oracle-japan.github.io/ocitutorials/beginners/creating-vcn/
VSCodeでCtrl+yが行削除になる不具合の解決

# 不具合
VSCodeで「Ctrl + y」でやり直しをしようとしたら行が削除される

# 原因
VSCodeにインストールした拡張機能が悪さをした

# 解決
1) キーボードショートカットを開く
![キーボードショートカット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873482/e58c4f7b-eeeb-80b3-2192-e688054715a5.png)

2) キーボードショートカットの設定タブで「Ctrl y」を検索
![キーボードショートカットタブ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873482/09af50cd-421a-941d-6d21-669c3153e014.png)

3) 拡張機能によって Ctrl + y に設定された行削除のキーバインドを削除
![解決.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873482/5df30983-bdf0-792e-385e-bec2eca76cd1.png)

# [追記]

- 「Ctrl + d」 に関して、[複数選択に使用](https://qiita.com/TomK/items/3b1f5be07d708d7bd6c5#ctrl--d--command--d)できるはずだったが、行のコピーになる
- 上と同じ方法でキーバインドを検索すると、また拡張機能が悪さしていた
- 「選択した項目を次の一致項目に追加」という既定のコマンド以外を削除して解決した
【環境構築】UbuntuにMySQL環境を作ろうとして激ハマりした

VirtualBoxのUbuntuにて、MySQLを使おうとしたところ
環境構築中にエラーでハマった。

```
$ pip install mysqlclient
Collecting mysqlclient
  Using cached mysqlclient-2.1.0.tar.gz (87 kB)
  Preparing metadata (setup.py) ... error
  error: subprocess-exited-with-error
 
  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> [1 lines of output]
      ERROR: Can not execute `setup.py` since setuptools is not available in the build environment.
      [end of output]
 
  note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
```

下記記事を参考にさせていただき、無事解決。
https://qiita.com/Ken227/items/02482710e297ef691c8e
【Next.js / React】URLのクエリパラメータで状態を指定する 【Recoil / Jotai】

## 現在表示しているページを、URLだけで再現できるようにしたい

今個人で開発中のアプリで、上記の機能がどうしても欲しいと考えていました。
例えば
`https://myapp.com/?name="taro"`
でアクセスしたら、 name のステートの値が "taro" になっている状態にしたい。という具合です。

## Recoil

元々手軽なので Recoil で状態管理をしていました。 Recoil 自体にそういった機能がないのか調べていたところ `recoil-sync` なるものがあるらしく、
早速使ってようと思ったのですが、まだ未実装のようです。 (ドキュメントにはあるのですが)

https://recoiljs.org/docs/recoil-sync/introduction/

## use-query-params

というわけで別のライブラリを探していたところ、 `use-query-params` を使ってやる手法もあるそうで、
それを色々触っていたのですが、Next.js で動かすようにするには工夫が必要らしく、
[next-query-params](https://www.npmjs.com/package/next-query-params)というパッケージもあるそうなのですが、結構ややこしそうなので、手軽にできるライブラリを探しました。

## Jotai

https://jotai.org/

そうすると、 Jotai というライブラリーがかなり直感的で利便性が高いそうなので、これを用いることにしました。
使い方も recoil とほとんど同じ。
以下、こんな感じで使えます。(recoilの使い方を知っている人向け)

``` _app.tsx
import { Provider as JotaiProvider } from "jotai";
...
      <JotaiProvider>
        <Component {...pageProps} />
      </JotaiProvider>
```

``` src/state/jotai/hoge.ts
import { atom } from "jotai"

export const hogeState = atom("defaultの値")
```
``` src/components/foo.tsx
import { useAtom } from "jotai";
import { hogeState } from "@/state/jotai/hoge"

export const Foo = () => {
  const [hoge, setHoge] = useAtom(hogeState)
  ...
```

上記は Recoil の基本的な使用方法を Jotai で置き換えただけに過ぎません。
ここで、 atom の書き方を以下のように変更するだけで、状態を自動的にURLへ反映してくれます。

``` src/state/jotai/hoge.ts
import { atomWithHash } from "jotai/utils";

export const hogeState = atomWithHash('hogeHoge',"defaultの値");
```

このようにした後に、例えば `setHoge(100)` などで値を変更すると、
`http://localhost:3000/#hogeHoge=100`
のようにURLへ反映されます。

また、このURLを用いてアクセスすると、 `hoge` が `100` の状態でそのページがレンダリングされます。
すごい手軽です！！

## 結論

Jotai とっても便利！
Recoil でも似たような機能が実装されそうなので、それができたらそっちも触ってみたいです。


## 参考

https://betterprogramming.pub/how-and-why-you-should-store-react-ui-state-in-the-url-f2013a204cb2