OmniAICreator/Qiita-1.07M huggingface dataset:
宝くじ (paizaランク C 相当) Java解答例

# 問題文
https://paiza.jp/works/mondai/c_rank_skillcheck_archive/lottery

# 解答例
```java
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		try (Scanner scanner = new Scanner(System.in)) {
			int b = scanner.nextInt();
			int n = scanner.nextInt();
			for (int i = 0; i < n; i++) {
				int a = scanner.nextInt();
				if (a == b) {
					System.out.println("first");
				} else if ((a + 1) == b || (a - 1) == b) {
					System.out.println("adjacent");
				} else if (a % 10000 == b % 10000) {
					System.out.println("second");
				} else if (a % 1000 == b % 1000) {
					System.out.println("third");
				} else {
					System.out.println("blank");
				}
			}
		}
	}
}
```

# 補足
下4桁が一致するかどうかは10000で割った余りを確認すればよい（下3桁のチェックも同様）。
当たり前だが1等は2等と3等の条件も満たし、2等は3等の条件も満たす。そのため条件の厳しいものから先にチェックしないと正しい解答を得られないため注意する必要がある。
【React✖️Typescript】学習記録アプリを作って学んだこと

# はじめに
これまで段階的に学習記録アプリを作ってきました。今回は今までに加えてTypescriptとchakraUI、モックを利用したテスト等を導入して大変だった点やここまでの感想を共有できればと思います。
以前の記事達⬇︎

https://qiita.com/bisketoriba/items/2276b48af22511ae1db8

https://qiita.com/bisketoriba/items/52c238393d15326f0b7d

# この3週間で学んだこと
今まで作ってきた学習記録アプリで以下のような技術を導入しました。実装だけでなくテスト・デプロイなどアプリ開発に必要な最低限のステップは学習できたかと思います。~~ちゃんと理解できてるかは別。~~
- reactの基本
- typescriptの基本
- supabaseでのバックエンド構築
- jestでのテスト
- firebaseでのデプロイ
- github actionsでのCI/CD構築
- react-hook-formの基本
- chakraUIでのスタイリング

# 完成した学習記録アプリ
今までと大きく違うのはスタイリングにChakraUI、フォームの入力にreact-hook-formを導入している点です。ChakraUIを使うことでモーダルやスピナー等のコンポーネントを利用できるので、簡単にそれっぽいデザインを作れます。またreact-hook-formを使うことで今までuseStateで定義していたinput等の状態管理をせずにフォームを実装できます(バリデーションのエラー表示も楽)。

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3279945/4dfa3c14-65fc-1890-1ee8-f27288039501.gif)

~~gifが適当なのはスルーでお願いします~~

もしこのアプリに機能を加えるとしたら学習記録の検索やページネーション、日付を扱えるようにする、ダークモード対応などでしょうか？(今後本格的なアプリを作る際には導入していきたい)

# 大変だったこと
基本的な実装はTODOアプリみたいな感じですしこれまで作ってきた学習記録アプリと同じですが、ChakraUIやreact-hook-formは公式ドキュメントがほとんど英語になっているので導入するのが少し大変でした。なのでその辺りは序盤でやったudemyや適宜ネット記事やyoutubeで補完しました。また今回1番時間がかかったのはモックを利用したテスト実装で、google検索やaiに相談してもなかなか手こずりました。ここはメンターの方にも色々教えていただき何とか実装できました。Typescriptは型補完や問題のありそうなとこを警告してくれるのはいいですが慣れるまで少し時間がかかりそうです。(tsconfigの設定周りももう少し知る必要がありそう)

# ここまでで得た気づき
### アウトプット重視の学習が最速ということを実感
今回の学習記録アプリではreactでの実装だけでなくテストやデプロイ、cicdなどを取り入れました。もしこれらの技術を1つ1つudemy等の教材で学習していくとおそらく3週間では終わらないと思います。最低限のインプットをしたらあとはアウトプットをしながら学んでいくのが最速だということを実感できました。
### エラー解決の記事を書くことで将来の自分が助かる
自分は結構環境構築でエラーを出すことが多いのですが、エラー文をググると過去に自分が同じエラーの解決記事を書いていたりすることがあったので、遭遇したエラーの解決記事は他の人だけでなく未来の自分のためにもなるなと思いました。

# おわりに
学習記録アプリの作成を通して実装〜デプロイまでの一連の開発を体験できました。まだわからないことだらけですし各技術に対する理解度もそこまでないですが、一通りアプリ開発に必要最低限のステップをこの短期間(3週間くらい)で経験できたので着実に成長できている気がします。今後は世の中に価値を提供できるモノ作りができるように意識して学習していきます。ここまで見てくださりありがとうございました🙇

# JISOUのメンバー募集中
プログラミングコーチングJISOUではメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？

気になる方はぜひHPからライン登録お願いします:point_down:

https://projisou.jp
Git Bash for WindowsやVSCodeでベル(\a)音を鳴らす

bashでは`echo`コマンドで`ベル音`を出力することができます（シェルスクリプトが完了した際に音で通知させることができる）

```bash
echo -e "\a"
```
* echo はデフォルトでエスケープシーケンスを解釈しないため、`-e`をつける必要があります


## 上記のコマンドを実行しても音が鳴らない場合

Git Bashや、Windows Terminal側でベル音が鳴らないように設定されているため、下記設定を確認します

### ①「~\.inputrc」ファイルを作成して、ベル出力を有効にする

ホームディレクトリに`.inputrc`を作成して、下記内容を書きこみます
```bash
# none, visible or audible
set bell-style audible
```

下記ファイルを直接書き換えることで、変更も可能です（読み取り専用なので、メモ帳を管理者権限で起動して編集する）
"C:\Program Files\Git\etc\inputrc"

### ②Windows Terminalのベル設定を有効にする

「設定」⇒「Git Bash」⇒「詳細設定」の順で画面を開き、ベルの設定を変更します（音によるチャイム、にチェックをつけます）

![image](https://gist.github.com/user-attachments/assets/42bac983-b100-49e2-93dc-2a8b734ab67b)

## Visual Studio CodeのターミナルでBellを鳴らす

VSCodeはベルがデフォルトでOffになっているので、設定を変更します

* 「設定」画面で`accessibility bell`を入力して設定を表示させる
* 「sound」を`on`に変更して保存する

![image](https://gist.github.com/user-attachments/assets/00de5d6b-6b22-43b9-b201-9624e005f8da)
板と箱の接触解析

板と箱の接触解析をCyprien Rusuさんがyoutube上で公開されていたので、やってみました。普段使わない解析のため、動作チェックのみにとどめます。

使用ソフト：Salome-Meca 2018 for Windows


# １．解析の概要

板の全周を固定し、立方体を一定距離・方向に板へ押し付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782081/fb96382c-81bf-fad4-0bb9-886e25fe3417.png)

＜モデル＞
箱寸法：20mm立方体
板寸法：100mm角、厚み0.01mm
板と箱のヤング率：200000N/mm　ポアソン比0.3

＜拘束条件＞
板全周：全固定（X,Y,Z方向固定、X軸、Y軸、Z軸回り固定）
荷重：箱の上からZ方向に-１mm変位させる。
接触条件：箱の底を板接触させる。

＜メッシュ＞
箱：4面体1次要素（ソリッド）
板：3角形1次要素（シェル）

# ２．解析結果

箱周辺がZ方向に-1mm移動するのがわかります。よって、意図通り動作していると推定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782081/6b282177-aa3d-2b8a-b53e-475d75e0d9d5.png)


# ３．解析ファイル(*.comm)の設定を見てみる

接触条件の設定を中心に自分なりに読み解いてみました。contact1： 板の接触面、contact2： 箱の接触面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782081/fe6567e0-498c-e652-7f2d-beb623c5061c.png)

(2)板における箱との接触面の設定

---解析ファイルの内容----
CHNOR = CREA_CHAMP(identifier=u'9:1',GROUP_MA=('contact1', ),MODELE=model,OPERATION='NORMALE',TYPE_CHAM='NOEU_GEOM_R')

LIAISON_MAIL=_F(CHAM_NORMALE=CHNOR,
EPAIS=0.01,
GROUP_MA_MAIT=('box', ),
GROUP_NO_ESCL=('contact1', ), 
TYPE_RACCORD='COQUE_MASSIF'),MODELE=model)
---解析ファイルの内容----

板の接触部(contact1)の設定をします。NOMALE、NOEU_GEOM_Rの2点で、面の認識をさせている模様です。

LIAISON_MAILで板と箱の結合を設定します。組み合わせは、box(箱）とcontact1の２つに設定する。GROUP_MA_MAIT -> マスター側GROUP_NO_ESCL -> スレーブ側COQUE_MASSIFで、接触面の動きを定義しています。マスター側（箱）は、全方向(XYZ)のみ動くスレーブ側（板）は、全方向(XYZ)、全回転(X軸、Y軸、Z軸）動く

箱接触面（Contact2）を解析上でなにかしら設定しなくとも大丈夫なのか気になりました。

# ４．まとめ

動作を確認でました。後日、シェル要素とソリッド要素を組み合わせて解析するときに深堀しようと思います。動画を公開いただきましたCyprien Rusu様には貴重な動画を公開いただいことをお礼申し上げます。


＜参考資料＞

1)Cyprien Rusuさんがyoutube上で公開されていた動画です。
https://www.youtube.com/watch?v=k94VwXISxoU2

CodeAster公式ページのコマンド解説
Documentation - code_aster www.code-aster.org

[U4.44.01] Operators AFFE_CHAR_MECA et AFFE_CHAR_MECA_F
[U4.23.03] Operator ASSE_MAILLAGE
[U4.72.04] Operator CREA_CHAMP
Galaxy Watch 7 Wi-Fi・Bluetooth版 国内正規品 購入方法

Galaxy Watch 7はサムスンが製造するスマートウォッチです。

https://www.samsung.com/jp/watches/galaxy-watch/galaxy-watch7-44mm-green-bluetooth-sm-l310nzgjxjp/

ワンナンバー (スマートフォンとの電話番号共有) を利用するためには、LTE版が必要なため docomo や au の店舗・オンラインにてお買い求めください。

- docomo: https://www.docomo.ne.jp/product/scwatch7/
- au: https://www.au.com/mobile/product/plus-one/galaxy-watch-7/

# Wi-Fi・Bluetoothのみ対応でよければ直販や家電量販店で購入可能
https://www.samsung.com/jp/support/mobile-devices/about-directly-managed-store-in-samsung-and-official-retail-store/ によると正規販売店は下記のようですが、2024年8月現在取り扱いのない店舗もあるようです。(URLは44mmモデル)

- 直販: https://www.samsung.com/jp/watches/galaxy-watch/galaxy-watch7-44mm-green-bluetooth-sm-l310nzgjxjp/
- Amazon.co.jp: https://amzn.to/3SMuV41 (アフィリエイトリンクです)
- ビックカメラ: https://www.biccamera.com/bc/item/13154699/
- ヨドバシカメラ: https://www.yodobashi.com/product/100000001008586485/
- エディオン: https://www.edion.com/detail.html?p_cd=00078986725
- 上新電機: https://joshinweb.jp/watch/57531/4986773240422.html 
- ケーズデンキ: なし?
- ヤマダ電機: なし?
- ノジマ: なし?

# 要約
- 44mmモデルのみ比較となりますが、Amazonが最安値、直販とエディオンは同じ値段、ほかは若干高め
- ただし、8月11日までであればエディオンで5%引きにて購入可能 https://www.edion.com/special.html?identificationid=dcsale
- また、2024年8月末までバンドの購入補助キャンペーンも実施しているようです。詳しくは https://www.samsung.com/jp/explore/event/galaxy-watch-ultra-cpn/ をご覧ください。
[JS] 頻繁に使用する文字列、配列で似ているメソッドの違いを口頭で説明できますか？Part 1

# 似た動きをするメソッド
以下のメソッドたちは似た動きをするので、明確な違いを理解しておく必要がある
## slice vs splice
```js
const arr = [1, 2, 3, 4, 5, 6];

// slice
const sliceArr = arr.slice(0, 2); // [1, 2]
console.log(arr) // [1, 2, 3, 4, 5, 6]

// splice
const spliceArr = arr.splice(0, 2); // [1, 2]
console.log(arr) // [3, 4, 5, 6]
```
このようにsliceとspliceは~~同じく開始indexと終了index~~ 第一引数は開始indexと同じですが、第二引数はsliceは終了index、spliceは取り除く要素の数を引数として受け取っており、
返される配列は開始indexが0の時は同じものなのでよく混同しやすいです。

しかし、元の配列を確認してみるとsliceの場合は変化がありませんがspliceを使用したあとはspliceで返された配列の要素が抜き取られており、中身が変わってるのがわかります。

このようにsliceとspliceは得られる値こそ一緒ですがspliceの場合は元の配列に影響を及ぼすところが違いとなり、spliceは元の配列の要素を削除したい場合に使用して、ただ配列の一部を取得したいときはsliceを使うようにしましょう。
## slice vs substring
```js
const str = "123456";

// slice
const sliceStr = str.slice(0, 2); // "12"
const sliceStrNegativeIndex = str.slice(0, -2); // "1234"

// substring
const substringStr = str.substring(0, 2); // "12"
const substringStrNegativeIndex = str.substring(0, -2); // ""
```
どちらも開始インデックスから終了インデックスまでの文字列を返すところは一緒ですが、substringの場合は負のインデックスを使用した時に空の文字列が返されます。

なので、負のインデックスでの操作をしたい場合はsliceを使用して、そうじゃない場合はどちらでも大丈夫ですね。

sliceは先ほどのように配列でも使用できるところが便利です。
野球の審判 (paizaランク C 相当) Java解答例

# 問題文
https://paiza.jp/works/mondai/c_rank_skillcheck_archive/umpire

# 解答例
```java
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		try (Scanner scanner = new Scanner(System.in)) {
			int n = scanner.nextInt();
			int ballCount = 0;
			int strikeCount = 0;
			for (int i = 0; i < n; i++) {
				String s = scanner.next();
				if (s.equals("ball")) {
					ballCount++;
					if (ballCount >= 4) {
						System.out.println("fourball!");
					} else {
						System.out.println("ball!");
					}
				} else {
					strikeCount++;
					if (strikeCount >= 3) {
						System.out.println("out!");
					} else {
						System.out.println("strike!");
					}
				}
			}
		}
	}
}
```

# 補足
特になし。「ストライクが3つたまったとき」と「ボールが4つたまったとき」のみ特殊な処理になるので、そのチェックを優先する必要があるくらいか。
処理のネストが深くなってしまったので、ボールだった時とストライクだった時でそれぞれ関数を作成したほうが見やすかったかもしれない。
paiza×Qiitaコラボキャンペーンなので、恥を忍んで投稿します！

# はじめに
　paiza×Qiitaコラボキャンペーン ということ、過去に一度練習したことがあるランクB問題ですが、理解度の確認を兼ねて再度実施しました。
　不適切な部分について、ご指摘いただけるとありがたいです。

https://paiza.jp/works/mondai/b_rank_skillcheck_sample/long-table

# 私の回答例

```python
# coding: utf-8

N, M =map(int,input().split())
value =[[int(x) for x in input().split()] for _ in range(M)]

seat_availability = [True] * N #各シートが着席できるかどうか
guests_num = 0 #着席したお客の総数

for m in range(M):
    entering_num = value[m][0]  #入店したお客の人数
    seat_num = value[m][1] - 1  #着席する最初のシート番号
    
    #入店したお客が最大シート数をまたがない場合
    if seat_num + entering_num <= N: 
        if not False in seat_availability[seat_num : seat_num + entering_num]:
            #着席したお客の総数に今入店したお客の人数を加算
            guests_num += entering_num
            #当該シートにお客が着席
            seat_availability[seat_num : seat_num + entering_num] = [False] * entering_num
    
    #入店したお客が最大シート数をまたがない場合 
    else: 
        if not False in seat_availability[seat_num :] and not False in seat_availability[: ((seat_num + entering_num) % N)]:
            #着席したお客の総数に今入店したお客の人数を加算
            guests_num += entering_num
            #当該シートにお客が着席
            seat_availability[seat_num : seat_num + entering_num] = [False]* entering_num
           
print(guests_num) 

```
　座席 n と座席 1 が隣り合っており、プログラム上で表現する際、n で割った剰余を用いるところが、この練習問題の肝でしょうか
 
　解答コード例は、`for`を使用して1席ずつ確認するものでしたが、私は`in`で確認しました。違いはよく分かっていません。
 
　変数の名称も長くて読みづらいですね。英語が苦手でgoogle翻訳でその都度調べて変数名としているのが、原因のひとつかな。



https://qiita.com/hironori_narita/items/4b06db0953053d41c4a0

　Qiitaのストック記事を読み直します。
VB.net 基本的な文法（繰り返し1）for文

前回の記事では、VB.netのSelect文を記載しました。

https://qiita.com/HiHiroyoshi/items/718272b3a3187e47b6b7

今回の記事では、繰り返しとしてfor文を取り上げます。

配列（Array）の値を一つずつ抽出して、まとめてmessageに入れるといったことをプログラムで行います。

配列(array1)
|0  |1  |2  |
|---|---|---|
|A  |B  |C  |

数字の部分は、配列（array1）の添え字(index:通し番号)です。ポイントは、***1番目が0から始まる***ことです。
プログラミング言語によっては、添え字の始まりが違うこともあるので気を付けましょう。

さて、まずはarray1を宣言し、messageに付け加えていきましょう。

```
        Dim array1() As String = {"A", "B", "C"}

        Dim message As String = ""

        message = array1(0)
        message &= array1(1)
        message &= array1(2)

```

このように書くと、messageには、ABCという値が入ります。&=は、文字列の追加を意味します。
もっと、クールな書き方があるよ！
という方もいるでしょうが、初学者向けなのでこう書いています。

さて、このプログラミングではarray1()の要素("A"や"B","C")の数が3つと決まっているので、問題はありませんが、要素数が3つでない場合はどうするべきでしょうか？
その際の例の一つが、繰り返し(for)文を使ったものです。

```
Dim array1() As String = {"A", "B", "C"}

Dim message As String = ""



For i = 0 To array1.Count - 1

    message &= array1(i)

Next i

```

上記の書き方です。
この書き方であれば、要素数が3以外でもプログラムを変更する必要がないですよね。

ポイントは、iという使い捨て（スコープの関係のため）の変数を用意して、配列の0からarray1の要素数(3つ）から1を引いた数("C")までの値を取り出して、messageに付け加えている点です。初学者は、***要素数 - 1*** を忘れやすいので気を付けましょう。 試しに - 1 を取り除くと、indexOutOfRangeExceptionといった内容（配列の範囲外）が実行の際に起きるはずです。


## まとめ
繰り返しには、for文が使えないかを試してみましょう。
for文配列に対して利用する際には、要素数 - 1を忘れないようにしましょう。
みかんの仕分け (paizaランク C 相当) Java解答例

# 問題文
https://paiza.jp/works/mondai/c_rank_skillcheck_archive/mikan

# 解答例
```java
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		try (Scanner scanner = new Scanner(System.in)) {
			int n = scanner.nextInt();
			int m = scanner.nextInt();
			for (int i = 0; i < m; i++) {
				int w = scanner.nextInt();
				int result = w / n * n;
				if (result == 0) {
					result = n;
				} else if ((w - result) >= (result + n - w)) {
					result += n;
				}
				System.out.println(result);
			}
		}
	}
}
```

# 補足
公式の解答例だと愚直に箱の候補を作成してどれに一番近いか、みたいなのをチェックしている。分かりやすさで言えばこれのほうが良いと思うが、箱の候補が増えていくと計算時間に問題が出てくると思うので、一応解答例では別のものを作成した。

1. `w / n * n`を計算する。ひとまずこれの計算結果で箱が`x * n`か`(x + 1) * n`まで絞り込める
1. `w / n * n`の結果が0だった場合は（問題文の制限により0の箱には振り分けられないため）自動的に答えはnになる
1. `(w - result) >= (result + n - w)`の部分で`x * n`と`(x + 1) * n`のうちどちらのほうに近いかをチェックしている

ものすごいざっくりとした解説を書いたが、自分でも説明が分かりづらい。普通に公式の解答例を参考にしたほうがいいかも……
GASを使用してスプレッドシートからGoogle Driveに保存 【Google Apps Script】

# はじめに
今回は、表題の通り`Google Apps Script`を使用してGoogle spreadsheetsからGoogle DriveにJson形式で保存する方法を紹介したいと思います。
Googleアカウントさえあれば完結するので、興味のある方はぜひやってみてください！

## デモ
![画面収録-2024-08-11-15.21.08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/c1e59a0a-fde0-ed60-b77d-7e9cdd285576.gif)

このように、スプレッドシートの内容がjson形式で保存されていることが確認できます。
(nameについては生成されたダミーデータとなります)

## やりかた
ここからは実際にやり方を解説していきます。

### 1. スプレッドシートからGASの画面を開く

![スクリーンショット 2024-08-11 15.58.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/1a1aa131-d719-ee44-55bf-3321627b29dc.png)

画面上部のメニューから拡張機能→Apps Scriptを選択して、Google Apps Scriptのエディタが表示されたらOKです。

### 2. コードをコピペ

以下のコードをコピペします。
コードに簡単な解説コメントをつけているので、よければご覧ください。

```javascript
function getFormattedCurrentTime() {
  const now = new Date();
  const year = now.getFullYear();
  const month = ('0' + (now.getMonth() + 1)).slice(-2);
  const day = ('0' + now.getDate()).slice(-2);
  const hours = ('0' + now.getHours()).slice(-2);
  const minutes = ('0' + now.getMinutes()).slice(-2);

  const formattedTime = `${year}/${month}/${day}_${hours}:${minutes}`;
  return formattedTime;
}

function generateJsonFromSheet() {
  // 現在アクティブなスプレッドシートを取得
  const sheet = SpreadsheetApp.getActiveSheet();

  // シート名取得
  const sheetName =sheet.getSheetName()

  // データ範囲を取得（ヘッダー行も含む）
  const data = sheet.getDataRange().getValues();

  // 最初の行をヘッダーとして使用
  const headers = data[0];

  // データを配列に変換
  const jsonArray = data.slice(1).map(row =>
    headers.reduce((obj, header, i) => {
      return {
        ...obj,
        [header]: row[i],
      };
    }, {})
  );

  // JSON をフォーマットして出力
  const jsonToString = `${JSON.stringify(jsonArray, null, 2)};`;

  let folder;

  // 指定した名のフォルダを取得、なければ新規作成
  try {
    const folders = DriveApp.getFoldersByName('jsonFromSheet');
      folder = folders.next();
  } catch (error) {
    folder = DriveApp.createFolder('jsonFromSheet');
    Logger.log("Created new folder 'jsonFromSheet'");
  }

  // JSON スクリプトを Google ドライブに保存する例
  const file = folder.createFile(`${getFormattedCurrentTime()}-${sheetName}.txt`, jsonToString, MimeType.PLAIN_TEXT);

  Logger.log(`File created: ${file.getUrl()}`);
}

// スプレッドシート読み込み時に実行される関数を定義
function onOpen() {
  //メニューバーにJSON出力用メニューを追加
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const entries = [{
    name : "JSONでドライブに保存",
    functionName : "generateJsonFromSheet"
  }];
  spreadsheet.addMenu("JSON", entries);
};
```
`⌘+S`で保存できればこの工程は完了です。

### 3. 実際に動かしてみる

ここまでできたら、下画像のように`JSON`というメニューが表示されているはずなので、それをクリックしてみてください。(初回は権限の付与を求められるかもしれません)

![スクリーンショット 2024-08-11 15.59.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/9bb8d853-6e00-b645-7c7c-6fe81f954040.png)

"スクリプトが完了しました"とでたら、ドライブに`jsonFromSheet`というフォルダと、中に`日時-シート名.txt`のファイルが生成されていると思います。


## おわりに
お読みいただきありがとうございました！
ちょっとした効率化をするならやはりGASは強いですね。。。
Alexaを喋らせたいけど挫折している

通常であればこういう技術記事は『成功したこと』を書くべきだと思っていますが、Qiitaは成功したこと以外も書きやすく思えるので、残しておきます。

# やりたかったこと
![aws.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858763/6e826276-f45c-62e9-b50d-7fb4d9c2d331.png)
概要を図にすると上記となります。洗濯機とswitchbotを接続しているので、洗濯が終わるとswitchbotが検出できます。現在はそこからクラウドを経由してスマホに通知が飛ぶのですが、家庭内にあるAlexa（正確にはAmazon echo）でも喋らせたかったです。

問題なのはAlexaを喋らせる部分。というのも、Alexaは人間の問いかけをトリガーにするのが基本なので、問いかけをせずに喋らせるのがとてもハードル高いんです。
![aws2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858763/fbb2054f-366d-ed13-21be-8417a74a7125.png)

突然喋らせることが容易にできてしまうと「ある日突然あちこちのAlexaが大声で広告を叫ぶ」みたいなイタズラができてしまうので、そもそもそういうルートをなるべく潰しているのかもしれません。


# 試したこと
## Alexa スキル
Alexaを喋らせる、となると一番最初に検討されるのがこの機能。Amazonが公式で提供している手段です。

が、前述のように音声をトリガーとするのが基本なので却下。

## alexa-remote-control
一番有力な方法だけれど、2024年8月時点ではなかなか難しい方法。

https://github.com/thorsten-gehrig/alexa-remote-control

上記のgithubで公開されているシェルスクリプトを叩く方法です。Alexaに喋らせたい場合にはこれを使うケースが多いようです。

これを使う上での課題は現時点で2つあります。

1. スクリプトを叩く環境 (PC) の確保
2. スクリプトに設定するアカウント情報

スクリプトを叩くと発話するので、洗濯機の動作が終了したときにスクリプトを叩くPCを用意する必要があります。最初はスクリプトを叩くためにRaspberry Piを常時起動しておこうか？とも考えていましたが、AWS Lambdaを使うと無料でできそうだったので、PCの確保という問題は解決でした。

問題は2のアカウント情報。以前はメールアドレスとパスワードで使用できたんですが、現時点ではリフレッシュトークン (REFRESH_TOKEN) が必須になってしまったようです。AWSでAlexa用のアカウントを作ってみたり、ライブラリを入れてみたり、Alexa-cookieというツールを使ってみたりしたのですが、リフレッシュトークンを取得することができず。

https://github.com/Apollon77/alexa-cookie

Linuxからコマンドラインでやるなら上記のツールが楽かなと思ったのですが、ブラウザがないと難しそう。試しにEC2にSSHで接続してツールを動かしLynxというテキストベースブラウザで認証できないかと検討しましたが、captchaに阻まれてしまいました。

![20240810_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858763/08572af1-de12-3d8d-8eff-3356eb4b994d.png)

このあたりで「ブラウザがない環境でリフレッシュトークンを取得するのは無理なのでは？」と挫折し始めています。


# これから

今のところはalexa-remote-controlを使わずに発話させる方法がなさそうなので、何とか発話させられないかを検討しています。トークン取得さえできてしまえば発話させるところまで進めると思うので、あと一歩がなかなか進まないという状況ですね。

ネットで検索して出てくる情報だとリフレッシュトークンがいらない時代のものばかりなので、割と絶望的な気もしていますが。。。
poetry runに失敗したときに

#　はじめに
AIに関連して今まで学習していなかったpythonに手を出したのですが、まだ文法とかを学習しているだけで、ツールなどの使い方が良く分かっていません。
そのため、いろいろなチュートリアルなどで実行したものの、エラーになって進めないということが何度かありました。
今回はその中の一つについて、自分が対応できたものをメモとして書いておきます。
きっと後で見直すと、「なんてところで躓いてるんだ・・・」となりそうな気がしますがメモとして投稿しておきます。

# poetry run app でエラーになった
こんなエラーです

```cmd
$ poetry run app
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/*****/*****/__init__.py", line 1, in <module>
    from .manager import ExecutionManager
......
    from xxxxxxx.data.block import Block
  File "/home/*****/*****/data/block.py", line 7, in <module>
    from prisma.models import AgentBlock
ModuleNotFoundError: No module named 'prisma.models'
```

最後のあたりですね。
ModuleNotFoundError: No module named 'prisma.models'
となってます。

とりあえず調べて解決方法にたどり着いたので、記しておきます。
ちなみになぜこれで解決できるのかはまだ理解できていません。。。

# 解決策

```cmd
$ poetry run prisma generate
(実行結果)
Prisma schema loaded from schema.prisma
```

これでエラーにならなくなりました。
初心者が忘れがちなSQLの構文のポイント

# 背景
基本情報技術者試験んでSQLについて広く浅く勉強した記憶があるが、
いざ実務で　group by を使用すると、
条件絞り込みをするのがhavingであることを忘れていた。
この際少し基礎を振り返るべきと思い再勉強。

# 目的
常に使うような構文のポイントを洗い出して、
いつでも使用できるようにすること

# 本文

## where in は　where 条件1 or 条件2 と同じ
```sql
where id in (1,2,3);
where id = 1 or id =2 or id = 3;
```
## selectの引数と戻り値は2次元表
テーブルを入れたら、テーブルが返ってくる。

## group by はカットして集計する
何別に分けたいか？がカット、
カットしたものに対してどのような処理を適用したいか？が集計。
カットだけするのがwindow関数。

## havingはgroup by後のテーブルをイメージ
groupby後のテーブルをイメージし、条件かけたいカラムにwhereと同じように条件をかける。

## サブクエリはビューみたいなもの
下記においてビュー名の部分は本来select文。
つまりサブクエリとビューはかなり似てる。
```sql
select * from ビュー名
```

## case文はどこにでも書ける
selectの後しか使ったことがないが、where,group by など、ほとんどどこにでもかける。

## 集合演算(union)は、完全重複レコードは削除してくれる
unionで、縦に2つテーブルを合体する際に、完全に重複するレコードは削除される。

## nullは値ではないから''(セミコロン)がいらない。
文字列型は''がいる。

# 学び、次に意識したいこと
少し使わないとすぐ忘れてしまいますね。。。。
できるだけ業務で少しDBを触る際など、ちょくちょく試していきたい。
line-bot-sdk-python v3 で位置情報メッセージの送受信がうまく行かない！

## はじめに
`line-bot-sdk-python` が `version3` になってからのドキュメントや記事などが少なく、ユーザが送信した位置情報メッセージのハンドリングに詰まったので解決策を共有します。

## 環境
- Python3.11
- line-bot-sdk 3.9.0
- Flask 2.3.3

## 発生したこと
`Flask`を利用してLINE Botを作成する際に，ユーザから送信されたメッセージの種類によって処理を変えたい場合， `@handler.add` を利用するが，LINE Bot SDKがv3よりも前の方法だとうまくできませんでした．

## 解決した方法
ドキュメントなどに記載がなかったので `line-bot-sdk` のGithubをたどりました．

https://github.com/line/line-bot-sdk-python/tree/master

その結果， `LocationAction`と`LocationMessageContent`が従来とは異なる場所に配置されてました．
以下，修正した`import`方法を共有します．(line-bot-sdkのlocation部分のみ抜粋)

`v3`より前の場合
```python
from linebot.models import LocationMessage, LocationAction
```

`v3`以降
```python
from linebot.v3.webhooks import LocationMessageContent
from linebot.v3.messaging.models.location_action import LocationAction
```

## おわりに
`line-bot-sdk`のバージョンが3になってからの記事がまだあまり出ていないので，位置情報以外にも画像や音声などのメッセージをハンドリングする方法もまとめて記事にしようと思います．

## 参考文献

https://github.com/line/line-bot-sdk-python/tree/master

https://qiita.com/siganai_poteto/items/c3863ec05a8a6517f167
AWS Systems ManagerからEC2インスタンスのコマンドを呼ぶときの注意点について

# はじめに
AW EC2上に配置したpythonスクリプトをAWS lambdaからSystem Manager(SSM)のRunShellScriptを利用して呼び出した際に、ログインユーザーに関する問題で躓いたので、問題の概要と解決策をまとめます。

### 参考にさせていただいたサイト
https://dev.classmethod.jp/articles/ssm-document-know/

# 問題点
SSMからRunShellScriptを実行した場合、実行ユーザーは`root`となる。
一方、EC2インスタンスに通常ログインした場合のユーザーは`ec2-user`となる。

`ec2-user`で構築した環境で動くスクリプトをSMS RunShellScriptから呼ぶと、実行時ユーザーが`root`となるため実行環境が異なり、`import module error`などが発生する。


```bash:SSMからRunShellScriptで実行した場合
$ pwd
/usr/bin

$ whoami
root

$ which python3
/usr/bin/python3
```

```bash:EC2にSSH接続した場合
$ pwd
/home/ec2-user

$ whoami
ec2-user

$ which python3
~/.pyenv/shims/python3
```

# 解決策
以下のサイトでは、AWS Systems Managerドキュメントを使用していますが、RunShellScriptでも同じこと。
実行時ユーザーを`ec2-user`に変更することで実現できます。

```bash
$ su - ec2-user -c "実行したいコマンド"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222220/908fd22f-ba92-0a9d-6a4f-1292364b1243.png)

```bash:結果
/home/ec2-user
ec2-user
/home/ec2-user/.pyenv/shims/python3
```

したがって、lambdaからEC2インスタンス上のスクリプトを呼ぶ場合も、このように実行時ユーザーを変更することで可能となりました。
```python:lambdaスクリプト(抜粋)
import boto3

ssm = boto3.client('ssm')

# Run   Command実行
response = ssm.send_command(
    InstanceIds = [instance_id],
    DocumentName = "AWS-RunShellScript",
    Parameters = {
        "commands": [
            "su - ec2-user -c 呼び出したいコマンド",
        ]    
    },
)
```

https://dev.classmethod.jp/articles/ssm-document-know/

## うまくいかなかった解決策
以下のように、実行時ユーザーを変更した上でスクリプトを呼び出した場合はうまくいきませんでした。
```bash:うまくいかなかった例
$ sudo su - ec2-user
$ 呼び出したいコマンド
```
[TypeScript] 型のカスタマイズをしてみた(branding)

同じnumberでも以下のように単位が異なるとこがある
``` ts
const length: number = 80; // cm
const weight: number = 80; // kg
```

この場合、両方numberであるため、厳密なチェックができなくなる
``` ts
const calLength = (length: number) => {
    return length * 2
}

const calWeight = (weight: number) => {
    return weight * 2
}
```

## Brandingを使ってみる
`as`でしか指定できないデメリットはあるが、以下のような書き方で単位の指定をして使うことができる。
``` ts
const length = 80 as number & { __brand: 'cm' }; // cm
const weight = 80 as number & { __brand: 'kg' }; // kg
```
そうすると厳密なチェックができるようになる。
``` ts
const calLength = (length: number & { __brand: 'cm' }) => {
    return length * 2
}

const calWeight = (weight: as number & { __brand: 'kg' }) => {
    return weight * 2
}
```

## 終わりに

暗号化されたものか複合化されたものかをチェックしたり、同じ型でももっと厳密に型定義を行いたいときにはこれを使っていきたいと思った。

調べているとTypeScriptには知らない技法が多くて面白い
【2024年08月版】ProxmoxVE8 で ipv6 を無効にする方法

# はじめに

Proxmoxで作業中のこと

Google に Ping うつか。。。

```
# ping www.google.com
PING www.google.com(xxxxxx.yyyy.xxx (####:####:####:###::####)) 56 data bytes
  :
  :
```

なんで、ipv6 つかうの。。。
つかわんねんけど。。。

# 設定方法

`/etc/default/grub` を編集して、`update-grub` します

```diff 
- GRUB_CMDLINE_LINUX_DEFAULT="quiet"
+ GRUB_CMDLINE_LINUX_DEFAULT="quiet ipv6.disable=1"
```

```terminal
# update-grub
# reboot
```

:::note info
`/etc/network/interface` ファイルを覗いて、ipv6の記述があるようなら、
Proxmoxのコンソールの`System` -> `Network` からipv6の設定も削除しておきましょう
:::

# 確認

## 変更前

```terminal
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
```

## 変更後

```terminal
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
  :
  :
```

# さいごに

かんたんでしたね
Fizz Buzz (paizaランク C 相当) Java解答例

# 問題文
https://paiza.jp/works/mondai/c_rank_skillcheck_sample/fizz-buzz

# 解答例
```java
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		try (Scanner scanner = new Scanner(System.in)) {
			int n = scanner.nextInt();
			for (int i = 1; i <= n; i++) {
				if (i % 3 == 0 && i % 5 == 0) {
					System.out.println("Fizz Buzz");
				} else if (i % 3 == 0) {
					System.out.println("Fizz");
				} else if (i % 5 == 0) {
					System.out.println("Buzz");
				} else {
					System.out.println(i);
				}
			}
		}
	}
}
```

# 補足
- 値が指定の数の倍数かどうかは、その数で割ったときの余りが0になるかどうかをチェックすればよい
    - Javaであれば%による演算で余りを確認できる
- `i % 3 == 0`や`i % 5 == 0`のチェックの前に`i % 3 == 0 && i % 5 == 0`のチェックを持ってくるのがポイント。これが前後すると、例えば15等の3の倍数かつ5の倍数が来た時に正しい答えを得られない

Fizz Buzz問題はたまに企業のスキルチェックとかで出てきたりするので、一応こういう問題も解けるようになっておいたほうが良い。
VB.net 基本的な文法（判定編2）Select文

前回の記事では、判定文のIf文を取り上げました。
https://qiita.com/HiHiroyoshi/items/d8e82fb303da6861169d

今回の記事では、Select文を取り上げたいと思います。
（SQLのSELECT文とは、混同しないように気を付けましょう。）

前回のIf文では、ネスト（入れ子）にしていくと、 **プログラムのコード** が読みにくくなるといったことを指摘しました。

今回のSelect文では、場合分けがキーワードです。

例えばある変数group(分類)を例に考えます。
このgroupはString型（文字列）で、A,B,C,D,Eの5種類のデータが記載されているとします。

|分類 |値  |
|---  |--- |
|A    |1   |
|B    |2   |
|C    |3   |
|D    |2   |
|E    |5   |

分類ごとに、上記の値をscoreに入れるプログラムを作成してみましょう。まずは、If文を例に出します。

```
Dim group As String = "A"

Dim score As Integer

If group = "A" Then
    score = 1
ElseIf group = "B" Then
    score = 2
ElseIf group = "C" Then
    score = 3
ElseIf group = "D" Then
    score = 2
ElseIf group = "E" Then
    score = 5

End If

```

こういった形です。
これと同じ動作をSelect文を利用して書いてみます。

```
Dim group As String = "A"

Dim score As Integer

Select Case group
    Case "A"
        score = 1
    Case "B", "D"
        score = 2
    Case "C"
        score = 3
    Case "E"
        score = 5

End Select
```

こういったプログラムのコードになります。
 ***読みやすい（可読性が高い）*** ですよね！
また、BとDの場合は、同様の値を入れるため、
カンマ区切りでつなげることも可能です。

## まとめ

場合分けの場合は、Select文にできないか検討してみましょう。
2つの日付の差分を求めるプログラム

`chmod +x dt.py`で、実行権を付け、`./dt.py`で動かして下さい。
入力のプロンプトが現れ、2つの日付を入力すると、日数の差を出力します。

for example. 
入力時に`1/1/1 1967/5/11`等とやると、西暦が始まってから1967年5月11日は何日目だったかを表示します。


```dt.py
#!/usr/bin/python3
#
# 2つの日付の差分を求めるスクリプト
#
#Usage: python3 dt.py
#

import datetime
def main():
    s1,s2=input("Input YYY1/M1/D1 YYY2/M2/D2:").split()
    y1,m1,d1=(int(x) for x in s1.split('/'))
    y2,m2,d2=(int(x) for x in s2.split('/'))
    dt1 = datetime.datetime(y1, m1, d1)
    print("Date1:",dt1)
    dt2 = datetime.datetime(y2, m2, d2)
    print("Date2:",dt2)
    td = dt2 - dt1
    print("Diff:",td)
    return

if __name__=="__main__":
    main()
    exit(0)

```

#### 実行例

```
$ dt.py
Input YYY1/M1/D1 YYY2/M2/D2:1967/5/11 1988/5/17
Date1: 1967-05-11 00:00:00
Date2: 1988-05-17 00:00:00
Diff: 7677 days, 0:00:00
```
Pythonの内蔵関数を活用した高速な文字列操作

## はじめに
Pythonでは、文字列操作に関する内蔵関数が多数用意されています。これらの内蔵関数を活用することで、文字列操作の高速化やメモリの節約を図ることができます。本記事では、代表的な内蔵関数を紹介し、それらを使った高速な文字列操作の方法を解説します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/4ba555f5-9167-85b0-89ac-396381fc6b5d.png)

### 1. `join()`を使った文字列の結合

文字列の結合には、通常は`+`演算子を使うことが一般的です。しかし、大量の文字列を結合する場合は、`join()`内蔵関数を使う方がはるかに高速です。以下は、`join()`を使った文字列の結合の例です。

```python
# `+`演算子を使った場合
list1 = ['a', 'b', 'c']
result1 = ''
for item in list1:
    result1 += item

# `join()`を使った場合
list2 = ['a', 'b', 'c']
result2 = ''.join(list2)

print(result1)  # abc
print(result2)  # abc
```

上記の例では、大量の文字列を結合する場合に、`join()`を使うことで、通常の方法よりもはるかに高速に処理できることがわかります。

### 2. `split()`を使った文字列の分割

文字列を分割する場合は、通常は`split()`内蔵関数を使います。以下は、`split()`を使った文字列の分割の例です。

```python
text = 'a,b,c'
result = text.split(',')
print(result)  # ['a', 'b', 'c']
```

上記の例では、カンマ区切りの文字列を分割する場合に、`split()`を使うことで、簡単に分割できることがわかります。

### 3. `replace()`を使った文字列の置換

文字列の置換には、通常は`replace()`内蔵関数を使います。以下は、`replace()`を使った文字列の置換の例です。

```python
text = 'hello, world'
result = text.replace('world', 'Python')
print(result)  # hello, Python
```

上記の例では、特定の文字列を別の文字列に置換する場合に、`replace()`を使うことで、簡単に置換できることがわかります。

## まとめ

本記事では、Pythonの内蔵関数を使った高速な文字列操作の方法を紹介しました。文字列操作に関する内蔵関数を活用することで、コードの高速化やメモリの節約を図ることができます。実際に内蔵関数を使ってみて、コードの高速化やメモリの節約を図ることができることを確認してください。
CodePipelineによるCI/CDパイプライン構築で詰まった箇所

#### 起きたエラー
AWSのコンソールに以下の文字が出力される。
「error code: ecs_update_error; error message: the ecs service cannot be updated due to an unexpected error: the container backend did not have a container port 80 defined. (service: amazonecs; status code: 400; error code: invalidparameterexception; request id: addae102-e782-4dc8-aa60-35bd40c4b3bb; proxy: null). check your ecs service status」

80番ポートは開いていないよ。
という意味。

#### 原因
![port80.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/453af997-23fb-8a08-1723-a9cd4c53d86c.png)
バックエンドでNestJSを使用していることをすっかり忘れていた。
NestJSのデフォルトポートは3000番。
80でなく3000を指定する。

#### 正しくはこう書く
![appspec.ymlの間違い.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/1f09cfd4-cae8-7cee-9639-1678bba5f50f.png)



#### buildspec.ymlの誤り

![buildspec.ymlの間違い.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/84aca950-ef42-6fa8-3384-6c8644209967.png)

#### taskdef.jsonの誤り

![taskdef.jsonの間違い.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/c245f3c7-9972-b9e0-d9dc-c5211a6e0c22.png)

tags[]が残っているとエラーが出力される。

lock sequence entries are not allowed in this context at line 22
忘れずに消す。
ポテトチップスの方程式

# はじめに
ポテトチップス（以下ポテチ）は、面白い形をしている。それは、上から見ると楕円形であり、横からだと双曲線に見える。そこで、今回はそのような摩訶不思議な形をしているポテチを3次元的にモデル化して以下のようなグラフにしてみることを目的とする。
![potechi_wire.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/78cfab14-4a3a-0b25-1fea-c5931fdde274.png)

# ポテチの方程式
早速だが、上記のようなポテチを描くための方程式は以下のように表すことができる。

```math
\begin{equation}
\left\{ \,
    \begin{aligned}
    & \frac{x^2}{a^2}+\frac{y^2}{b^2}<1 \\
    & z = \frac{x^2}{a^2}-\frac{y^2}{b^2} \\
    \end{aligned}
\right.
\end{equation}

```

ただし、$a>0,b>0$とする。

第一式はご存知の通り楕円の方程式であり、第二式は双曲線の方程式である。

# プログラム
以下のようなプログラムを描いた。これは、ポテチの領域を黄色でワイヤーフレームを用いて描写するものである。

``` python potechi_wire.py
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib.colors import ListedColormap
import japanize_matplotlib
fig = plt.figure()
ax = fig.add_subplot(projection='3d')

a=1
b=2

n=100

x=np.linspace(-2,2,n)
y=np.linspace(-2,2,n)

X,Y=np.meshgrid(x,y)

Z=np.zeros((n,n))

for i in range(n):
    for k in range(n):
        # 楕円の方程式（領域外は空にする）
        if X[i][k]**2/a**2+Y[i][k]**2/b**2>1:
          Z[i][k] = np.nan
        else:
          # 双曲線の方程式
          Z[i][k]=((X[i][k])**2)/a**2-(Y[i][k]**2)/b**2
        
ax.set_title("ポテトチップス", fontsize=25)
ax.set_xlabel("X", fontsize=20)
ax.set_ylabel("Y", fontsize=20)
ax.set_zlabel("Z", fontsize=20)
# ワイヤフレームを用いてプロットした点をつなぐ
ax.plot_wireframe(X,Y,Z,color="yellow")
plt.savefig("potechi_wire.png")
plt.show()
```

さて、これを実行すると以下のようになる。

![potechi_wire.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/78cfab14-4a3a-0b25-1fea-c5931fdde274.png)

# まとめ
今回は、ポテトチップスの概形を描くためのプログラムを作成した。そのためには、楕円と双曲線の方程式を用いる必要性があった。このように、数学は見えないところで世界に影響を与えているということを我々は再認識する必要性があると思われる。
「単体テスト」はソフトウェア単体、それとも機能単体のどちらのことか？

## はじめに
システム開発の際は、言葉の定義を確認する場面が多々ありますが、「単体テスト」について若手に質問を受けたので共有しておきます。
単体テストには、「ソフトウェアの単体テスト」という意味で呼ぶ会社もあれば、「機能の単体テスト」という意味で呼ぶ会社もあるので注意しましょう、という話です。

## 今回の話の工程

![今回の話の工程](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/c63c99cd-99b8-8edc-ac95-a9bbdb535e15.png)

システム開発工程のテスト工程は、単体テスト・結合テスト・システムテスト（総合テスト）と呼ばれることが多いのですが、「単体テスト」については、「ソフトウェアの単体テスト」という意味で呼ぶ会社もあれば、「機能の単体テスト」という意味で呼ぶ会社もあります。

割合としては、機能単体テストのことを「単体テスト」と呼びことが多いとは思いますが、これらの違いも含めて整理しておきたいと思います。

## ソフトウェア単体テスト（ユニットテスト）

「単体テスト」という言葉を、「ソフトウェア単体レベルのテスト」という意味で使う会社があります。

会社によって、
・ソフトウェア単体テスト（略して、単体テスト）
・ユニットテスト（略して、UT）
などのような呼び方があります。

（私の経験上は、ソフトウェア単体テストは「ユニットテスト」と呼ぶことが多いと思います）

### ソフトウェア単体テストのテスト観点について

それぞれのテストの違いを理解するために、テスト観点についても補記しておきます。

ソフトウェア単体テストは、その名の通り、ソフトウェア単体での品質を確認するためのテストで、実装の元となった詳細設計書からテストケース（テスト条件・期待値）を設定して確認をしていきます。

「ソースコードからテストケースを洗い出せば、全ての条件が網羅できるんじゃないの？」と感じるかもしれませんが、詳細設計書からの実装漏れを検出できるように詳細設計書からテストケースを設定します。

なお、テストケースについては、テスト条件の抜け漏れ防止や、テスト結果（期待値）の認識違い防止のためにデシジョンテーブルなどを用いて整理することが多いと思います。

![開発したシステムをテストしよう！テスト工程を効率よく着実に進めるためのポイント](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/78a5d2bb-3669-9d44-f49a-453d3accc036.png)

出典： [type『開発したシステムをテストしよう！テスト工程を効率よく着実に進めるためのポイント』](https://type.jp/s/itac/article23.html)


こういった表を用いてテストケースを整理した上で、ソースコードと突き合わせて抜け漏れ確認（つまり、カバレッジ確認）を行います。

定量的なカバレッジの測定をするために、JavaであればJUnitでテストコードを実装することが多いと思います。例えば、以下の例では、Color1.java(赤線)のカバレッジが86.7%（合計命令数が15に対してカバー命令が13）なので未実施のものがあることがわかります。

![Java Eclipseでカバレッジを取得するサンプル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/f0e01e28-c884-e85a-9216-3778efdc19da.png)

出典： [ITSakura『Java Eclipseでカバレッジを取得するサンプル』](https://itsakura.com/java-eclipse-coverage)


## 機能単体テスト（ソフトウェア結合テスト）

「単体テスト」という言葉を、「機能単体レベルのテスト」という意味で使う会社があります。

会社によっては、
・ソフトウェア結合テスト
・機能単体テスト（略して、単体テスト）
・単機能テスト
などのような呼び方がありますが、私の経験上では、こちらを「単体テスト」と呼ぶことが多いような気がします。

基本設計書で記載されている単体機能となるので、
　画面仕様：　１画面
　帳票仕様：　１帳票
　バッチ仕様：　1バッチ（ジョブ）
　API仕様：　1API
といったように、各機能のドキュメント単位に検証をしていきます。（バッチの場合は、当段階で「ジョブ単位」での検証を行い、次工程の結合テストにて「ジョブネット単位」の検証を行う）

### ソフトウェア単体テストのテスト観点について

それぞれのテストの違いを理解するために、テスト観点についても補記しておきます。

機能単体テストは、その名の通り、機能単体での品質を確認するためのテストで、機能単体の仕様を記載している資料（つまり、基本設計書）を元にテストケースを設定して確認をしていきます。

以下のようなテスト仕様書と、前述のデシジョンテーブルを組み合わせたりして、テスト条件の網羅性を確認します。

![出典：テスト仕様書の書き方～テストケース作成のポイント～](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/c9a2a558-41e9-36a8-1546-140fe9adf5fd.png)

出典：[SHIFT『テスト仕様書の書き方～テストケース作成のポイント～』](https://service.shiftinc.jp/column/8223/)


## おわりに
ということで、「単体テスト」については、ソフトウェア単体テストなのか、機能単体テストなのかの言葉の定義は注意しましょう。

なお、結合テストについても内部・外部といった曖昧さを含みますが、新入社員研修などで教育を受ける基礎知識なので、今回は割愛します。
CodeBuildででたエラー

#### エラー概要
![エラーログ箇所.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/c9f2486d-771e-d4c2-abb7-ec01bd2e3508.png)
"build"なんてコマンドは存在しないと怒られる。。。
しかし、packages.jsonにはしっかり"build"コマンドが記載されていた。
いったいなぜ。。。

#### 原因
![buildspec.ymlの内容.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/42c99926-f750-4362-29ad-73464038d7d2.png)

この書き方だと、ビルド実行するコンテナ内のカレントディレクトリで、
「$ docker build -t $REPOSITORY_URI:latest -f ./packages/backend/Dockerfile」
を実行せよという命令になってしまう。
正しくはカレントディレクトリでなく、ローカルと同じ./packages/backendディレクトリで実行されるべき。

#### 解決法
![正しくはこう書く.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280830/9f97906e-79c6-34e7-cbc1-ac0bc25d3d10.png)

実行先のディレクトリをきちんと記述する。
monorepo構成でDockerfileが複数あるのはよくあることなので、ビルドがどこで実行されるのか、コンテナの中身を頭の中でイメージする。
バグとの対話：今日もまた挑戦している

## プロローグ：新たな朝

朝日が差し込む窓辺で、
モニターの青い光が希望を灯す。
昨日の挑戦の跡、
エラーログは新たな道標。

コーヒーを一口、深呼吸。
今日もまた、バグとの創造的な対話が始まる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/09fbf58d-b329-dd51-d618-56b23ca25de9.png)

## 第1章：バグの声を聴く

```
console.log("ここから新たな発見が始まる");
// 予期せぬ動作の中に、イノベーションの種が眠る
```

デバッグの技は、
バグの声なき声を聴くこと。
エラーメッセージは、
コードの進化を促す
小さなヒント。

ブレークポイントを置き、
変数の中身をのぞき込む。
そこには、
予想外の可能性が広がっている。

## 第2章：挑戦という名の冒険

再現性なきバグは、
未踏の地を探検するようなもの。
時に姿を現し、
時に影に潜む。

```python
def explore_bug():
    if random.random() < 0.1:
        return "新たな発見だ！"
    return "探検は続く..."
```

100回に1回しか現れないバグ、
その瞬間を捉えるために、
何度でも挑戦する探究心。

## 第3章：デバッグの哲学

バグを理解することは、
コードの可能性を広げること。
エッジケースという名の、
イノベーションの源泉へ足を踏み入れる。

```
if (edge_case) {
    // ここで何が起こっているのだろう？
    // 新たなソリューションの誕生の瞬間
}
```

想定外の入力、
境界値の挙動、
並行処理の複雑さ。
そこには常に成長の機会がある。

## 第4章：進化の喜び

長い探求の末、
新たな解決策を見出した瞬間。
心の中で創造の歓びが湧き上がる。

```git
git commit -m "Enhance: バグの根本原因を解明し、システムを進化させた
- 予期せぬ動作からより堅牢な設計へ
- エッジケースの対応力を強化
- パフォーマンスと可読性を大幅に向上"
```

慎重に考え抜いた改善で、
システム全体が進化する瞬間。
デバッグの先にある、
限りない成長の可能性。

## エピローグ：終わりなき挑戦、果てしなき進化

バグとの対話は、
終わりのない進化の物語。
新しいコード、新しい機能、
そこには常に新たな挑戦が待っている。

それこそが、
プログラマーの創造の源。
今日の挑戦は、
明日のイノベーションとなる。

```python
while True:
    challenge = face_new_bug()
    knowledge = learn_from(challenge)
    improve(self, knowledge)
    celebrate_growth()
```

コードを閉じる時、
達成感と共に新たな好奇心が芽生える。
明日もまた、新たな挑戦が始まること。
それこそが、この仕事の醍醐味。

モニターを消し、心躍る期待とともに家路につく。
バグは敵ではない、進化のパートナー。
共に成長し、共に新たな地平を切り開く。
終わりなき挑戦の旅は、まだ始まったばかり。
【殿堂入りキャンペーン】残り物の量 (paizaランク C 相当) Java解答例

# 問題文
https://paiza.jp/works/mondai/c_rank_skillcheck_archive/leftover

# 解答例
```java
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		try (Scanner scanner = new Scanner(System.in)) {
			float m = scanner.nextFloat();
			float p = scanner.nextFloat();

			float temp = m - (m * p / 100.0F);

			float q = scanner.nextFloat();
			System.out.println(temp - (temp * q / 100.0F));
		}
	}
}
```

# 補足
- m, p, qは全て整数だが、最終的に実数の計算を行うため初めからfloatとして取得して計算している
  - 当然intとして取得して計算時にfloatかdoubleにキャストするようなやり方でもよい
- 面倒だったのでtempという変数名を使ったが、こういう名前の付け方は正直あんまりよくない
- 浮動小数点演算になるので、解答例だと厳密に正しい計算結果は得られない（[参考](https://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html)）。今回の問題は`真値との誤差が0.0001 未満`で正解としてくれるのでこれでもよいが、より厳密な計算結果が欲しい場合は[BigDecimal](https://docs.oracle.com/javase/jp/8/docs/api/java/math/BigDecimal.html)を使うとよい
  - ただしBigDecimalによる計算は結構遅かった気がするので、実務等で本当に必要かどうかは要件と相談

```java
import java.math.BigDecimal;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		try (Scanner scanner = new Scanner(System.in)) {
			BigDecimal m = BigDecimal.valueOf(scanner.nextInt());
			BigDecimal p = BigDecimal.valueOf(scanner.nextInt());

			BigDecimal temp = m.subtract(m.multiply(p).divide(BigDecimal.valueOf(100)));

			BigDecimal q = BigDecimal.valueOf(scanner.nextInt());
			System.out.println(temp.subtract(temp.multiply(q).divide(BigDecimal.valueOf(100))));
		}
	}
}
```
WindowsでのReact環境構築をしてみた

# Reactの勉強をするためにViteを利用してReactの環境構築をしてみました。

## 1.Node.jsをインストールする

1-1.[公式サイト](https://nodejs.org/en)にあるインストーラーを使用してインストール

1-2.コマンドプロンプトでバージョン確認してインストールできたことを確認
```
node -v
npm -v
```

### ---なぜNode.jsをインストールするの？---
・Node.jsに付いてくるnpmというパッケージ管理ツールでReactで使うパッケージの管理を簡単にするため
・ローカル開発サーバーを使って開発アプリの動作を確認するため

## 2.Viteの環境構築構築をする


2-1.以下のコマンドでViteプロジェクトを作成する
```
npm create vite@latest
```
2-2.作成するとプロジェクト名は何にするか聞かれるので任意のプロジェクトを入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853126/8bb855d4-90cd-ec49-eaaa-806b2c7c7873.png)

2-3.使用するフレームワークを選択する。ここではReactを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853126/cc1828b8-b730-10f2-af4b-fcc4af4ce6ac.png)

2-4.今回僕の環境ではTypeScriptを使わないので「JavaScript　＋　SWC（コンパイラ）」を選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853126/414a5c60-8a44-65b1-415b-3ef7ca2cfc1b.png)

2-5.package.jsonに明示されている全てのパッケージをインストールする
```
nmp i
```

2-6.開発サーバーを起動する
```
npm run dev
```
サーバーのアドレスにアクセスして以下が表示されればok
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853126/1d63a9ab-ff42-ac26-9e41-df5f8cda33f8.png)
typing.NoReturn以降のコードをmypyは到達不可と判断

typing.NoReturnを返す関数以降のコードをmypyは到達不可と判断するようです。

しらなかった。

NoReturnは`raise Exception`に対する戻り値とする、と記事で読みました。

なので、そうしていました。

ただ、誤りは、別の型を返すにもかかわらず、`->NoReturn`とNoReturnしか返さないとしてしまうと、mypyが呼び出し元の関数以降に到達しない、とerrorを表示する。この意図がわからなかったので、簡易ながらメモ残します。


```python
def main():

    my_no_return():
    # 以降のコードをmypy/Pycharmの「問題」は到達不能と判断下し、解析しない

def my_no_return(clause:bool)->NoReturn: #ここはException以外もあるため` NoReturn|None`とするのが正解
    if clause:
        raise Exception("hogehoge")
```
Javaで「直前の文字を繰り返す文字列にマッチするパターンを記述する」の動作を確認してみた

# 概要

Javaで「直前の文字を繰り返す文字列にマッチするパターンを記述する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/regex/index10.html

# 実装

以下のファイルを作成しました。
```JSample10_1.java
import java.util.regex.*;

class JSample10_1{
  public static void main(String[] args){
    String regex = "Ha*n";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("Hn");
    System.out.println(m1.find());  // true

    Matcher m2 = p.matcher("Han");
    System.out.println(m2.find());  // true

    Matcher m3 = p.matcher("Haaaaaan");
    System.out.println(m3.find());  // true

    Matcher m4 = p.matcher("HaaYaan");
    System.out.println(m4.find());  // false
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample10_1.java 
$ java JSample10_1 
true
true
true
false
```

# まとめ

何かの役に立てばと。
React｜todoアプリが開発できて、開発の理解が深まるサイト

エンジニアのみなさま、日々の学習本当にお疲れ様です！
また本記事まで足を運んでいただき本当に感謝です。
約2分程度で読めるので最後まで読んでもらえると幸いです。

# 対象

- Reactのインプットが完了してお手頃なアプリを開発したい方
- フロントのみで実装したときの『データの流れ』を理解したい方

# サイトのURL

https://developer.mozilla.org/ja/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning

# アプリのご紹介

こんなアプリが開発できます。

![20240811.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744730/9eec1139-9d4a-ac70-9334-9391f0b54abf.gif)

# 何が学べるか？

### CRUDの開発

登録（Create）・参照(Read)・更新(Update)・削除(Delete)に加えて、参照後のtodoリストへの絞り込みの開発について学べます。

### コンポーネントの使い方

メインページを一通り開発した後、コンポーネント化できる箇所をピックアップします。
具体的には『Todo』『FilterButton』『Form』コンポーネントとしてファイルの切り出しをします。切り出す時の開発手順が学べます。

### propsの使い方

コンポーネント間（親と子という表現をよく使います）でデータの渡す時の書き方です。
JSXにpropsを渡すことで、同じコンポーネントを複数利用したとき、コンポーネントごとに名称を変更したり、ブール値を設定したい時の開発手順が学べます。

### フックの使い方

データの状態監視（初期表示や更新）で使う『useState』をメインに、フックの開発手順が学べます。今回のアプリでは『useState』の他に以下2つのフックも使います。

#### useRef

DOMへのアクセスする時・再レンダリングに影響を与えずに値を保持する時に使う

#### useEffect

コンポーネントを外部システムと同期させる時に使う

## その他

- 注意点としては英語を翻訳した日本語になっているため、少し読みづらさはあります
- 後半は英語のみになります
- TypeScriptの開発は本アプリでは未対応です
- バックエンドの開発は未対応です

# さいごに

弊社のご紹介もさせてください。

▼ コーポレートサイト

https://prum.jp/

▼ Wantedly求人

https://www.wantedly.com/projects/626662

弊社メンバーは学習した内容を日々Qiitaの記事にアウトプットしております。
弊社にご興味のある方、まずは求人を見てみてください！
ご応募お待ちしておりますー！

### 最後までご覧いただき、ありがとうございました！
lambdaで "Runtime.ImportModuleError" の解消

## lambdaで Youtube Data APIを使おうとしたところ、 "Runtime.ImportModuleError" が発生
今までAWSにはほとんど触れずに来たのだが、仕事で知識が必要になってきたため、Lambdaを触ってみることにした。ちょうど、家でYoutubeを見ながらエクササイズに励んでいるため、[Youtube Data API](https://developers.google.com/youtube/v3/code_samples/code_snippets?hl=ja&apix_params=%7B%22part%22%3A%5B%22snippet%2CcontentDetails%22%5D%2C%22id%22%3A%5B%228j9L9h3ODfU%22%5D%7D) で、動画のIDからの再生時間を取得する処理を作ってみることにした。コードのサンプルは、ありがたいことに、[Youtube Data API](https://developers.google.com/youtube/v3/code_samples/code_snippets?hl=ja&apix_params=%7B%22part%22%3A%5B%22snippet%2CcontentDetails%22%5D%2C%22id%22%3A%5B%228j9L9h3ODfU%22%5D%7D) のページから出力できるので、それを少しだけ修正して、lambda handlerに転記した。

``` python

# Sample Python code for youtube.videos.list using API Key
# See instructions for running these code samples locally:
# https://developers.google.com/explorer-help/code-samples#python

import googleapiclient.discovery
import googleapiclient.errors

def lambda_handler(event, context):
    api_service_name = "youtube"
    api_version = "v3"
    api_key = "your api key" 

    # Create an API client
    youtube = googleapiclient.discovery.build(
        api_service_name, api_version, developerKey=api_key)

    request = youtube.videos().list(
        part="snippet,contentDetails",
        // まずはサンプルで固定値
        id="8j9L9h3ODfU" 
    )
    response = request.execute()

    print(response)

```

実行してみると、以下のようなエラーが発生した。

```
{

  "errorMessage": "Unable to import module 'lambda_function': No module named 'googleapiclient'",

  "errorType": "Runtime.ImportModuleError",

  "requestId": "b3dd46ce-4ccf-4a60-9389-215b55c04768",

  "stackTrace": []

}
```

## lambda レイヤーにライブラリのzipをアップしてみるが直らない
ライブラリのコードをアップしていないので、それはそうだと思い、調べるとlambda レイヤーというところにアップするのが一般的だそうだ。以下を参考にzipファイルをアップしてみるも、全く直らず、途方に暮れた。
https://qiita.com/_YukiOgawa/items/66832f704be1218b09c4
lambdaレイヤーというのは、ライブラリや設定ファイルなどをアップしておける場所だそうだ。[この記事](https://qiita.com/__DASHi__/items/268062f0dba0e93170f2)の説明がわかりやすかった。

## zipにするディレクトリ名が重要だった！
あれこれ調べた後に、もう一度最初の記事を読むと、 "pythonはLambdaレイヤーにアップロードするフォルダ名称と必須なので、ここは変えないようにしてください。" と記載があった！自分の場合、zipにする前のディレクトリ名を適当につけており、これが原因で失敗していた。ということで、zipにする前のディレクトリ名を "python" にしてアップロードすることで、無事解決した。

[python以外のディレクトリ名](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/packaging-layers.html)

## おまけ： Cloud9が使えず混乱
上記を調べる過程で、[ローカル環境が干渉してしまい、うまくいかなかった](https://qiita.com/hiro_f/items/6b7d724cd16947479ecf)という記事を見かけた。ということで、AWSのCloud9を使ってみようとするものの、アクセス権がないという画面になってしまった。AWS知識が乏しいもので、四苦八苦しながら権限を確認するものの、権限はあるように見える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661656/b96743e5-f0e1-fe2f-22b1-fb3abf14c184.png)
どうやら、サービスの新規利用を停止していたようだ。
https://www.itmedia.co.jp/news/articles/2407/31/news173.html
権限がないと思い込んだが、たしかによくみると、"詳細はこちら"のページに "we have made the dicision to close new customer access to AWS Cloud9" とある。lambdaレイヤーもCloud9もAWS用語の見慣れなさに惑わされて、説明をよく読んでいないことで時間を浪費することになった。気をつけなければいけない。
Open3D便利帳

自分用
順次更新

## 点群データの初期化
```python
import open3d as o3d
pcd = o3d.geometry.PointCloud()
```

## 可視化
クラスにしておくと便利

```python
class VISUALIZE():

    pc = o3d.geometry.PointCloud()
    
    def __init__(self, pc):
        # ウィンドウの作成
        self.vis = o3d.visualization.Visualizer()
        self.vis.create_window()
        self.vis.clear_geometries()

        # 座標軸の作成と描画
        coordinate_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=500, origin=[0, 0, 0])
        self.vis.add_geometry(coordinate_frame)

        # 点群の登録
        self.pc = pc
        self.vis.add_geometry(self.pc)

        # 点群の大きさ
        render_option = self.vis.get_render_option()
        render_option.point_size = 10.0

    def update(self, pc):
        # 点群の更新
        self.pc = pc
        self.vis.update_geometry(self.pc)

        # 描画の更新
        self.vis.poll_events()
        self.vis.update_renderer()

    def destroy(self):
        self.vis.destroy_window()
```

```python
VIS = VISUALIZE(pcd)

for i in 何らかのループ
    何らかの処理
    VIS.update(pcd)

VIS.destroy()
```

## Numpyへ変換
```python
import numpy as np
pdc_np = np.asarray(pcd.points)
```

## jsonにして記録

```python
txt = '{'
for i in 何らかのループ
    何らかの処理
    formatted_pts3d = ','.join([f"[{p[0]:.1f},{p[1]:.1f},{p[2]:.1f}]" for p in pdc_np])
    txt = txt + '"pcd":['  + formatted_pts3d + '],'
```
Azure Cache for Redis をプレビューコンソールと .NET で試してみた

Azure Functions から Azure Cache for Redis とやりとりするプログラムを実装する事を検討しており、その前に単体で Azure Cache for Redis の使い方をキャッチアップするために、プレビューコンソールと .NET で試してみました。

## 検証用の Azure Cache for Redis を作成

```bash:bash
prefix=mnredis
region=japaneast

az group create \
  --name ${prefix}-rg \
  --location $region

az redis create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-redis \
  --location $region \
  --sku Basic \
  --vm-size c0
```

## プレビューコンソールで試す

![azure-cache-redis-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/d23c67cf-5d1f-3573-45bc-e3b083d9d7d6.png)


## Azure Cache for Redis のプライマリキーを取得

```bash:bash
pkey=$(az redis list-keys \
  --resource-group ${prefix}-rg \
  --name ${prefix}-redis \
  --query primaryKey \
  --output tsv)
```

## 検証用の .NET コンソールアプリを作成

```bash:bash
dotnet new console --name $prefix

cd $prefix

dotnet add package StackExchange.Redis

cat <<EOF > Program.cs
using StackExchange.Redis;
    
var connectionString = "$prefix-redis.redis.cache.windows.net:6380,password=$pkey,ssl=True,abortConnect=False";
var redisConnection = ConnectionMultiplexer.Connect(connectionString);

IDatabase db = redisConnection.GetDatabase();

bool wasSet = db.StringSet("favourite:flavor", "i-love-rocky-road");

string value = db.StringGet("favourite:flavor");
Console.WriteLine(value);

var executeResult = db.Execute("ping");
Console.WriteLine(executeResult.ToString());

redisConnection.Dispose();
redisConnection = null;
EOF
```

## 検証用のコンソールアプリを実行

```bash:bash
$ dotnet run

i-love-rocky-road
PONG
```

## 後片付け

```bash:bash
az group delete \
  --name ${prefix}-rg \
  --yes
```

## 参考

https://azure.github.io/redis-on-azure-workshop/labs/01-explore-azure-cache-for-redis.html