OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者】Gitの備忘録

先日Gitについて学ぶ機会がありました。
いままで正直なんとなくGitを使っていたこともありこちらで整理しておきます。
# GitとSVN
これら二つはともに、ファイルの版管理や変更履歴を管理することのできるバージョン管理システムです。
違いは一言でいうとリポジトリがどこにあるかというところにあります。

※リポジトリ 　情報、成果物を格納しておくための保管場所

## SVN
SVNは集中型と呼ばれる管理方式をとっています。 この方式ではファイルと変更履歴がサーバー一つに格納されます。
- メリット<br>操作が簡単なこと

- デメリット<Br>集中管理しているため各個人でのバージョン管理ができないこと

## Git
分散型と呼ばれる管理方式です。この方式では各々がローカルにリポジトリを持っており、リモートリポジトリにプッシュするということを行います。

- メリット<Br>各個人でバージョン管理ができること<Br>各個人がリポジトリを持っているためサーバが使えなくなっても復旧できること
- デメリット<Br>覚えることが多いこと



現在はGitでのバージョン管理の方が主流のようです。


## Gitの概念と機能

ここからはGitの機能についてまとめます。主に使用する機能として以下のものがあります。


- ブランチ　<Br>同じリポジトリ内で履歴を分けることができます。そうすることで他のブランチに影響を与えることなく並行した開発を行うことができます。ブランチを作ることを「ブランチを切る」と表現します。


- チェックアウト <Br>ブランチを切り替えること。切り替えるときには「スタッシュ」を行うことでコミットしていない内容を退避させることができます。

- コミット <BR>ローカルリポジトリにファイルの変更を記録すること。
- プッシュ <Br>ローカルリポジトリの変更内容をリモートリポジトリに反映させること。

- マージ　<Br>指定した二つのブランチを統合すること。


- リベース <BR>ブランチの根元(親コミット)を別のコミットに付け替えること。指定したブランチの変更内容が取り込むことができます。



- プル <Br>リモートリポジトリから最新の変更を取得、そしてそのまま現在のブランチにマージを行うこと。


- フェッチ <Br>リモートリポジトリから最新の変更を取得すること。マージは行いません。




## おわりに

以前フェッチとプルの違いは？と聞かれたときにはっきり答えられませんでした。あまり知らずに使用するのはかなり危険ですよね。
これからGitを使う機会は多くなると思うのでなんとなく使うよりしっかり理解していて使っていこうと思います。見ていただきありがとうございました！
GitHubとDiscordを連携させたい

# やりたいこと

GitHubでの変更を、Discordで通知したい。

![スクリーンショット 2023-12-26 15.56.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/b851ea20-e752-59fa-8dbe-94493bfd7e4b.png)

# やり方

Discordのチャンネルの編集から

![スクリーンショット 2023-12-26 15.58.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/9a27c77f-5cc2-1160-2510-b5b4ecdb04ff.png)


webhookを作成し、URLをコピーする

![スクリーンショット 2023-12-26 15.58.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/ae5f325e-f877-9de6-89d0-83f76db602a3.png)


URLは以下のようになっているはず

`https://discord.com/api/webhooks/xxxx/yyyy`

これに+`/github`を付け足す

↓修正後

`https://discord.com/api/webhooks/xxxx/yyyy/github`


GitHubのSettingsから、Webhooksを追加する
![スクリーンショット 2023-12-26 16.02.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/fb492dba-6dd8-ed3d-0969-432fbb52a092.png)


Content typeを`application/json`に設定し、通知のタイプを選択。
![スクリーンショット 2023-12-26 16.03.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/b899dea1-02df-a9f8-bfff-7c8aa1718d9c.png)

以上で完了


# まとめ

`/github` の付け加えに少しつまづいた

# 参考
https://qiita.com/mycndev/items/c7417c4577341a8c4543
さや香の「見せ算」をChatGPTに実装してもらってみた

先日のM-1グランプリ決勝でさや香が披露したネタに出てきた「見せ算」をChatGPTに実装してもらいました。

# 見せ算のルール
見せ算のルールは以下ポストを参考にしました。
大学院ルールは割愛。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">理系としてさや香の「見せ算」、ルールまとめました<br>やりたい方いたらぜひ使ってください<a href="https://twitter.com/hashtag/M1%E3%82%B0%E3%83%A9%E3%83%B3%E3%83%97%E3%83%AA?src=hash&amp;ref_src=twsrc%5Etfw">#M1グランプリ</a> <a href="https://twitter.com/hashtag/%E3%81%95%E3%82%84%E9%A6%99?src=hash&amp;ref_src=twsrc%5Etfw">#さや香</a><a href="https://twitter.com/hashtag/%E8%A6%8B%E3%81%9B%E7%AE%97?src=hash&amp;ref_src=twsrc%5Etfw">#見せ算</a> <a href="https://t.co/dqw0Fdc8kT">pic.twitter.com/dqw0Fdc8kT</a></p>&mdash; ゆーき @26卒 (@y_kiguma) <a href="https://twitter.com/y_kiguma/status/1738907374709358823?ref_src=twsrc%5Etfw">December 24, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# プロンプト
入力したプロンプトは以下。
```プロンプト
#役割
あなたはpythonのプログラマーです。下記の依頼を満足するpythonスクリプトを記述してください。

#依頼
「見せ算」という独自の演算をする処理を実装してください。
「見せ算」は、任意の2つの自然数X、Yを"見せ"る演算です。
見せ算の演算結果（解）は"目"と表現します。

#ルール
「見せ算」のルールは下記です。
【基本ルール】
・X見せYとY見せXの眼は同じ。
・同じ数字どうしを見せ合った場合、その眼は「0」になる。
・違う数字どうしを見せ合った場合、その眼は大きい方の数字になる。
【特殊ルール】
・6見せ9 の眼は11
・2見せ5 の眼は1.1
・1見せ100の眼は83
```
表記揺れ（目と眼）がありますが、回答には影響出なかったようです。

# ChatGPTの回答

ChatGPT（GPT4）の回答は以下。
結構シンプルですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1402755/64d2701e-e62a-265c-06c3-d6f9b25c73b6.png)

```misesan.py
def misesan(x, y):
    # 特殊ルールのチェック
    if {x, y} == {6, 9}:
        return 11
    elif {x, y} == {2, 5}:
        return 1.1
    elif {x, y} == {1, 100}:
        return 83
    
    # 基本ルールのチェック
    if x == y:
        return 0
    else:
        return max(x, y)

# 例
print(misesan(6, 9))   # 11
print(misesan(2, 5))   # 1.1
print(misesan(1, 100)) # 83
print(misesan(4, 4))   # 0
print(misesan(3, 7))   # 7
```

# 実行結果
試しに実行したところ、正しく見せ算できているようでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1402755/cab6e7d6-5b5c-98fc-ff07-59d61730b4aa.png)


以上、「さや香の見せ算をChatGPTに実装してもらってみた」でした。
それでは。
その6

```
using Renci.SshNet;
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string host = "SFTPホスト";
        string username = "ユーザー名";
        string privateKeyFilePath = "秘密鍵ファイルのパス";
        int port = 22; // SFTPの通常のポートは22です
        string remoteFilePath = "/リモートのファイルパス";
        string localFilePath = "保存先のローカルファイルパス";

        try
        {
            using (var client = new SftpClient(host, port, username, GetPrivateKey(privateKeyFilePath)))
            {
                client.Connect();

                using (var fileStream = File.OpenWrite(localFilePath))
                {
                    client.DownloadFile(remoteFilePath, fileStream);
                }

                client.Disconnect();
            }

            Console.WriteLine("ファイルをダウンロードしました。");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"エラー: {ex.Message}");
        }
    }

    static PrivateKeyFile GetPrivateKey(string privateKeyFilePath)
    {
        string privateKey = File.ReadAllText(privateKeyFilePath);
        return new PrivateKeyFile(new MemoryStream(Encoding.UTF8.GetBytes(privateKey)));
    }
}
```
その5

```
using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        await CallWebApiAsync();
    }

    static async Task CallWebApiAsync()
    {
        using (HttpClient client = new HttpClient())
        {
            string apiUrl = "ここにWeb APIのURLを入力";
            
            try
            {
                HttpResponseMessage response = await client.GetAsync(apiUrl);

                // 応答が成功した場合
                if (response.IsSuccessStatusCode)
                {
                    string json = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(json);
                }
                else
                {
                    Console.WriteLine($"エラーコード: {response.StatusCode}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"エラー: {ex.Message}");
            }
        }
    }
}
```
データベース関連の基本的な用語

## 1.データベースとは何か
データベースは、情報を整理して保存するための仕組みやデータの集まりのことを指します。これにより、大量の情報を整理し、必要な時に素早く取り出すことができる。
## 2.DBMSとは何か
DBMSは、データベースを管理するためデータベースを管理するためのソフトウェアのことです。
データベースは膨大な量の情報を整理して格納する場所であり、その情報はテーブルと呼ばれる形式で組織されます。DBMSは、このデータベース内のテーブルを作成、更新、削除、検索するための機能を提供します。
つまり、DBMSはデータベース内の情報を効率的に管理し、プログラムがデータにアクセスできるようにするツールやシステムのことです。

## 3.RDBMSとは何か
RDBMSは、リレーショナルデータベースを管理するためのソフトウェアです。リレーショナルデータベースは、データを表形式で組織し、異なるテーブル間で関連を持たせることができるデータベースの一種です。
わかりやすく説明すると、RDBMSは大きなエクセルプレッドシートのようなもので、それぞれのシートがテーブルに相当する。各テーブルには特定の種類のデータが格納され。これらのテーブルは関連を持っています。RDBMSはこれらのテーブルを効率的に管理し、プログラムがデータにアクセスできるようにサポートします。

主要なRDBMSの製品として、MySQL, PostgreSQL, MicrosoftSQL Serverがあります。

## 4.SQLとは何か
SQLは、データベースにアクセスして操作データベースにアクセスして操作するための言語の一つです。SQLではコマンドを使い主に、データベース内の情報を検索、追加、更新、削除することができます。

## 5.テーブルとは何か
テーブルは、DB内で情報を整理して保存するための **表** のようなものです。テーブルはデータベース内で異なる種類の情報を保持するための領域で、各テーブルは特定のデータ型や属性を持った情報を格納します。

テーブルは行と列から構成されています。行はデータの実際のエントリ（レコード）を表し、列はそれぞれのデータ属性（フィールド）を示します。

簡単な例↓
```.diff
+----+-----------+------+
| ID |   Name    | Age  |
+----+-----------+------+
| 1  | Alice     | 25   |
| 2  | Bob       | 30   |
| 3  | Charlie   | 22   |
+----+-----------+------+
```
この例では、テーブルには３つのユーザーの情報が格納されています。各ユーザーの情報は行に対応し、列にはそれぞれユーザーのID、名前、年齢を表しています。

## 6.カラムとは何か
カラムは、DBのテーブル内で特定の種類のデータを格納するための垂直な部分を指します。**列**のようなもの。
```.diff
+----+-----------+------+
| ID |   Name    | Age  |
+----+-----------+------+
| 1  | Alice     | 25   |
| 2  | Bob       | 30   |
| 3  | Charlie   | 22   |
+----+-----------+------+
```
この例では、"ID", "Name", "Age"がそれぞれのカラムであり、各カラムには対応するデータが格納されています。

## 7.レコードとは何か
レコードは、DB内のテーブルにおいて１つの**行**に相当するものです。
```.diff
+----+-----------+------+
| ID |   Name    | Age  |
+----+-----------+------+
| 1  | Alice     | 25   |
| 2  | Bob       | 30   |
| 3  | Charlie   | 22   |
+----+-----------+------+
```
このテーブルでは、IDが1のユーザーの情報は「1 | Alice | 25」というレコードに対応しています。

## 8.クエリとは何か
クエリは、DBから情報を取得、追加、更新、削除するための命令文や質問文のことです。具体的には、SQLを使用してDBに対してクエリを発行します。

以下に、基本的なSQLもクエリの例を挙げてみます。

**SELECT:** DBから情報を取得するためのクエリ。
```.sql
SELECT 列名 FROM テーブル名;
```
**INSERT:** DBに新しい情報を追加するためのクエリ。
```.sql
INSERT INTO テーブル名 (列1, 列2, 列3) VALUES (値1, 値2, 値3);
```

**UPDATE:** DB内の既存の情報を更新するためのクエリ
```.sql
UPDATE テーブル名　SET 列名　＝　新しい値　WHERE 条件;
```
**DELETE:** DBから情報を削除するためのクエリ
```.sql
DELETE FROM テーブル名　WHERE 条件;
```
JavaScriptは「参照渡し」をしないって本当？

## 概要
タイトルの答えは**YES.**

JSを勉強し始めたばかりで、JSにおける値渡し/参照渡し/参照の値渡しの処理の違いがわかりませんでした。
調べていくうちに「え、JSって参照渡ししないんだ！？」となったので、ここに学んだことをまとめようと思います。

追記：いただいたコメントをもとに修正しました。コメントありがとうございます！

## 結論
- JSでの処理は「プリミティブ値は値渡し」「オブジェクトは参照渡し」と言われていますが、厳密には「参照渡し」はしません。
- JSでは「参照の値渡し」(共有渡し、本文中では共有渡しに統一)が行われています。

## 値渡し、参照渡し、共有渡しとは
- 値渡し
    - 引数に値を渡す時、変数の値をコピーして渡す処理。
        - 呼び出しもとの変数は変化しません。
- 参照渡し
    - 引数に値を渡す時、参照(=メモリ番地)で渡す処理。
        - 変更が呼び出しもとに反映されます。
- 共有渡し
    - 引数に値を渡す時、変数に格納されている参照をコピーして渡す処理。
        - 大抵の言語はオブジェクトを渡す時にこの形態になります。
        - 参照渡しと似ているように感じますが、実際には違う動きをします。

## JSにおける処理
言葉の意味だけではわかりづらいので、実際に挙動の確認をしてみましょう。
わかりやすいように「プリミティブ値は値渡し」「オブジェクトは参照渡し」と呼ばれているものの処理を比較します。

### JSの基本的な処理
値が生成されると、変数aにその参照が割り当てられます。
- 変数aに値10が渡された時の参照をS1とします。
    - 全てのサンプルコードにおいて、定義後の参照をS1、再代入後の参照をS2と表記しています。
    - サンプルコードは参考記事(下記掲載)の引用です。
- b = aを定義するとbにはS1が割り当てられます。
    - イメージ的には b → S1 → 10のようなたどり方をします。

```jsx
var a = 10 // S1
var b = a // bにS1が渡される

console.log(b) // 10
```

### 「プリミティブ値は値渡し」と呼ばれているものの処理
```jsx
var a = 10
var b = a

a = 100

console.log(b) // 10
```

```jsx
//解説

var a = 10 // S1
var b = a // bにS1が渡される

a = 100 // 再代入したのでa = 100にS2が割り当てられる

console.log(b) // bにはS1が渡されているのでS1 　= 10が成立
```

### 「オブジェクトは参照渡し」と呼ばれているものの処理
b = { val: 100 }が成立したことで参照渡しをしているように見えますが、実際は違います。
仮にJSが参照渡しであった場合、S1がS2に変更になります。

```jsx
var a = { val: 10 }
var b = a

a.val = 100

console.log(b) // { val: 100 }
```

```jsx
//解説

var a = { val: 10 } // S1
var b = a // bにS1が渡される

a.val = 100
// value値が100に変更
// 同じオブジェクトを操作しているため、aの参照がS2に変更されたわけではない

// bにはそのままS1が渡される
console.log(b) // { val: 100 }

//　参照渡しではない
```

## おわりに
もし誤りがあれば指摘いただけるとありがたいです。

## 参考記事
- [値渡しと参照渡しと参照の値渡しと](https://qiita.com/ur_kinsk/items/949dabe975bdc1affb82)
- [JavaScriptに参照渡し/値渡しなど存在しない](https://qiita.com/yuta0801/items/f8690a6e129c594de5fb)
- [値渡し・共有渡し・参照渡しを最小の例(5行)で端的に理解する](https://qiita.com/agajo/items/b21abdfb0baed340e897)
ボウリング Python3編

https://paiza.jp/works/mondai/array_utilization_primer/array_utilization_primer__bowling

配列に入れるのに苦労した。
※配列の入れ方は注意

```py
p = []
#１の位置
sum_pin = 0
#１じゃない残り
ans = 0

for i in range(4):
    p += input().split()

for i in range(10):
    if p[i] == "1":
        ans += 1
        sum_pin = 10 - i

print(sum_pin)
print(ans)

```
SpringBootでプロジェクト名変更

# この記事はこれの続きです

https://qiita.com/waokitsune/items/83febc4a0518d7d346aa

# リファクタリング機能でリネーム

プロジェクト上で右クリック → 『Refactor』 → 『Rename』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/893a52a3-845f-1997-6818-751e140a37f8.png)

demo → nekoに変えます。
『Update references』にチェック入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/7dbf009b-2a71-9c8a-a7a4-8e21b1f91088.png)

# ビルドエラーへの対応

リファクタリング機能でリネームしても下記のようなエラーになります。

> Project neko cannot be renamed, because it is in the default location.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/069abd76-7922-d190-ebbe-32ba5cbc28bd.png)

下記のようになっていますが、直すべきは『settings.gradle』になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/19876eca-bff7-8601-4b0a-b91565530db0.png)

**前のプロジェクト名のまま** なので…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/80b691a2-732e-118d-e596-78da0621970f.png)

新しいプロジェクト名へ変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/84556e20-a1ab-0e6c-bdc0-16989c65a79a.png)

# STSをいったん閉じてフォルダーをリネーム

STSはいったん閉じます。
プロジェクト名とフォルダー名を揃えておきたいのでリネームします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/bd9ec155-6f69-6785-930c-ffde1a780083.png)

# 旧プロジェクト情報を削除

STSを再度開くと下記のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/67f9df74-38d2-64d1-39a3-b1c6a8cdf55e.png)

これは右クリック → 『Delete』
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/75c4dc5e-8e8f-4874-1486-89109296d7b6.png)

この画面でも分かるように、前のフォルダー名の情報なので削除です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/0fc28fe8-4ba4-952b-34ac-5c8e5ff061e9.png)

# 新プロジェクトを開きなおす

『File』 → 『Open Projects from File System...』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/bf66c6c2-97a0-64f0-bf44-d0933edc776c.png)

リネーム後のフォルダーを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/5815d09c-924b-ce7f-12fc-2feac80adefa.png)

エラーが無くなり、想定通りにプロジェクト名変更できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/02c00656-672d-43c6-4b3b-67739d7721e7.png)

# Boot Dashboardから旧プロジェクト情報を削除

リネーム後、下記のようにプロジェクトをRun Asさせると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/547279a0-8e48-68a0-01c2-b2154283c3e7.png)

旧プロジェクト情報が残っているため、確認画面が出るようになってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/41bb83bb-3dcf-f1e0-bedb-b0c943d76fd5.png)

この確認が出ても問題は無いのですが、うっとおしいです。

そういった時は『Boot Dashboard』で旧プロジェクト上右クリック → 『Delete Config』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/95496d3f-2c6b-d72a-5cab-007999d3dfcf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/a9dcbc12-ea66-cfc1-d469-33a319e60383.png)

これでRun As時の余計な確認画面は出なくなりました。

# この記事の続き

https://qiita.com/waokitsune/items/f342f2f3b10df81d1679

# 参考サイトさん

https://qiita.com/Keita08/items/640219930423254b0ab3

# バージョン

Microsoft Windows [Version 10.0.19045.3803]
Spring Boot v3.1.7
【TypeScript】 ReactNodeの型

## はじめに
TypeScriptにて以下のようなエラーが出ました。
基礎的な内容ですが理解のために備忘録として残します。

![スクリーンショット 2023-12-26 15.18.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3591536/fded48d0-8ffa-e7c9-d8ab-69f16f9bd702.png)


## ReactNode
エラーの内容は「Date型はReactで表示できないよ」とTypeScritptが教えてくれている。

**ReactNode**とはReactコンポーネント(ボタン、テキスト、画像)やテキスト、数値など、Reactで画面に表示できるもの全てを表す言葉。
以下[公式より](https://reactnative.dev/docs/react-node)↓ ReactNodeが持つ型
>Boolean (which is ignored)
null or undefined (which is ignored)
Number
String
A React element (result of JSX)
An array of any of the above, possibly a nested one

```js
<blockquote className="font-bold text-slate-700">
{new Date(post.date).toDateString()}
</blockquote>
```
上記のようにすることでstring型にすることで解決
## おわりに
TypeScriptを使っていると今回のようなものに多く出くわす。最初は煩わしいと感じていたが教えてくれるのがありがたいと思うようになってきた。
引き続き学習を進めていきたい。
bash variable

```sh
#!/bin/bash

# Parse command line arguments
while getopts "f:" opt; do
  case $opt in
    f)
      file_name="$OPTARG"
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

# Check if the file_name is provided, exit if not
if [ -z "$file_name" ]; then
  echo "Error: File name not provided. Use -f option to specify the file name."
  exit 1
fi
```
ハッカソンで掃除をリズムゲーム化するアプリを作ってみた

# アプリの概要
掃除機のスライドを、取り付けたスマートフォンに搭載された加速度センサで検知し、リズムゲームの判定とするアプリです。
2020年の技育展で優秀賞をいただいた作品になります。
チームメンバーは私を含め3人で、私を除く2人はweb開発未経験でしたが2週間余りで作品を作ることができました。
![Videotogif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505295/89ec2183-130d-f1df-01e8-966f5d7ad796.gif)


github: https://github.com/ysdko/rhythmic-cleaner
デプロイURL: https://rhythmic-cleaner.vercel.app/


## 主な機能
* 楽曲・難易度選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505295/2a4c55b9-910c-5eb1-0dc9-9f84855ee419.png)

* リズムゲーム機能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505295/c1a668d9-bec4-73cc-037f-f7d7e08fc063.png)


* スコアのツイート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505295/3f56a50b-433f-3dff-eb79-5fee85c05de8.png)


## アーキテクチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505295/40427d4c-eb1c-676d-0feb-3cdf57f22631.png)


## アイデア出し
技育CAMPハッカソンというハッカソンイベントに参加した際に作成したものになります。
ハッカソンのテーマが「生活を豊かにするアプリ」で、そのテーマにあったアプリを考えることになりました。
アイデア出しには１週間ほどかけました。
最初は、Discordに各自が好きにアイデアまたは解決したい課題を投稿していくというやり方で進めて行きました。話を進める中で、「研究とアルバイトで部屋の掃除が、後回しになりやすい」という課題が全員の共通部分であることがわかりました。どうすれば解決を行えるアプリにするかと考えていた時に、当時流行っていたポケモンスマイルの広告を目にしました。このゲームは画像認識を用い、歯磨きの動作に合わせてポケモンが攻撃を行うという画期的なゲームでした。これをヒントに、掃除機をリズムゲーム化するという案を思いつきました。


## 技術選定
* スライドの判定をジャイロセンサを用いることにしました。
当初はポケモンスマイル同様画像認識で掃除機のリズム判定を行う予定でしたが、スライドの判定にラグが発生してしまう画像認識はリズムゲームには難しいと考え断念しました。その代わりとして、スマホに搭載されている加速度を取得するジャイロセンサを使うことにしました。

* 言語はjavascript, htmlでライブラリはphinaJSというゲーム開発用のものを採用しました。
私以外のメンバー２人が初めてのweb開発ということもあり、言語はjavascript, htmlでライブラリはphinaJSというゲーム開発用のものを採用しました。
デプロイについてはVercelで動かしています。

## 開発
開発はGithubでイシューを発行し、優先度やメンバーのレベルを考慮しながら割り当てていきました。
最初はリズムゲーム、ジャイロセンサによる加速度取得、譜面の作成に分かれて行い、開発が終わったメンバーからリズムゲームの開発に加わってもらうことにしました。
リズムゲームの実装に関しては以下の記事を参考に開発を進めていきました。
Phina.jsとリズムゲーム開発の実装全般についてわかりやすく説明されており、かなり参考になりました。
https://qiita.com/pentamania/items/399d133e5440c9424bde


## 改善
ハッカソンの審査員や私の両親に実際にアプリを使った感想をヒアリングしました。最初に作成したUIについてなどからダメ出しを受けました。それはUIが拙く、全体的な色やボタンの形の統一感がないという点です。これについてはメンターについていただいた企業のエンジニアの方にどうしたら統一感のあるUIにできるか？という質問をしました。メンターのエンジニア曰くUIデザインを考える上で、配色のバランスを重視すると良いというアドバイスをいただきました。具体的な考え方を以下に記載します。

#### UI作成における配色の考え方
一般的に画面上での色の配色を「70：25：5」の比率にして配色すると、バランスの取れた美しい配色になるとされています。
最も大きな面積を占める色が「ベースカラー（70％）」、アプリののイメージカラーとなる色を「メインカラー（25％）」、画面にアクセントを持たせるための色を「アクセントカラー（5％）」と呼びます。

https://chot.design/concept-of-design/02d49c79f19a/#:~:text=%E6%9C%80%E3%82%82%E5%A4%A7%E3%81%8D%E3%81%AA%E9%9D%A2%E7%A9%8D%E3%82%92%E5%8D%A0%E3%82%81%E3%82%8B,%EF%BC%85%EF%BC%89%E3%80%8D%E3%81%A8%E5%91%BC%E3%81%B3%E3%81%BE%E3%81%99%E3%80%82

# 苦労した点と学んだこと
実装の方向性をめぐり、チームの方向性を一つにしなければいけなかったことが最も苦労しました。一通りアプリが完成した時に、多くの機能を搭載すべきという意見とメンターに指摘いただいたUIの改修に注力すべきという意見に分かれました。私は、アプリ開発をする上でユーザーの期待に応えることを最優先と考え、チームの目標をUIの改修に注力した方がよいのではないかということをメンバーに説得しチーム全員の合意が取れた上でUI改修に臨むことができました。結果的にメンターの指摘通りにUIが修正されたことが評価され優秀賞を獲得することができました。この経験から、ハッカソンおよび実際に世に出すアプリ作りにおいては「自分たちが作りたいもの」よりも「ユーザーが使いやすいもの」を意識して作ることが重要だと改めて感じました。
Dockerのネットワーク作成によって、何をしてもCORSエラーが変わらない問題とバトルした(解決済み)

# 起きたこと
samでyamlに書かれている通りにapi gatewayを構築して、go言語で書かれたLambdaを使ってAPIを作成するが、Lambda側でもyaml側でもcorsの許可設定しているのに、何をやってもcorsエラーが変わらなかった。

環境構築資料の通りに進めていたが、そのブランチが古いことを後から知り、最新のブランチのREADME.mdにある手順でやっても他の人は成功するのに自分だけうまくいかなかった。

色々調べて、ほとんどの記事は「corsを許可したらいける」で、一部「"*"だとうまくいかないので直接指定する必要がある」という記事とか色々あったが、どれも関係はなかった。

# 解決方法
古い手順の中で、docker network createしていたのが原因だった。このネットワークのせいでyaml側とLambdaのheaderでのCORS設定が意味のないものとなってしまったのだろう。

コンテナを全て停止、削除して、そのネットワークを削除してこのネットワーク作成の手順を除いて再度構築し直したら問題なく動作した。
忙しい方のための Instana Advent Calendar Quiz 2023 鬼モード

2023年 Instana Advent Calendar 完走お疲れさまでした。
https://qiita.com/advent-calendar/2023/instana

Instana Advent Calendar Quiz 2023 はいかがでしたでしょうか？
https://qiita.com/h1nakamu/items/14982e4c5d686316f35c

# えっ。物足りない！？

ええ。わかっております。そんな方のために鬼モードを準備しました。
文字が多くて読んでる間に時間切れになるんですが、そこを含めての鬼モードということでご理解くださいm(_ _)m

....通常版含めて問題作るのめっちゃ大変でして。設問の品質に関しては察してやってください。

**それでは張り切ってどうぞー！**
※一人でクイズに参加するためには、kahoot のアカウントが必要です
https://play.kahoot.it/v2/?quizId=5de41542-cf3a-4478-8e37-9445a06eb86f
場所取り (paizaランク C 相当)

https://paiza.jp/works/mondai/array_utilization_primer/array_utilization_primer__line_up


参考になったのは

https://qiita.com/Atsulabo/items/14b63e43f8dbab0698cb

https://qiita.com/Atsulabo/items/f7467fbf69e89d2b1f94


１）とりあえずデータを取得しておく
２）ポップ関数で要素を頭から減らす
３）重複は1つだけにして減らしてB配列として定義
４）出力

```py
N,K,F = map(int,input().split())

A = [int(input()) for _ in range(K)]
for i in range(F):
     A.pop(0)

#重複取り除いたのをB列へ
B = []
for i in range(len(A)):
    if i == 0:
        B.append(A[i])
    else:
        for i in range(len(A)):
            if A[i] not in B:
                B.append(A[i])

#順番はそのままで出力
print(*B,sep="\n")
WinMergeで比較ウィンドウが全部無くなったらWinMerge自体も自動で閉じてほしい

# やりたいこと

こうやって比較をした後に…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/7c3da1b1-0457-f916-558c-6762f7707e14.png)

Ctrl + W で比較ウィンドウを閉じた際、下記のようにWinMerge自体が残ってしまいます。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/91109f71-d575-a0ae-d9c8-e811a92ceb5e.png)

比較ウィンドウを閉じる → WinMerge自体を閉じる の **二度手間** になることが多いです。

比較ウィンドウが全部無くなったらWinMerge自体も閉じてほしいです。

# 『Ctrl + Wで閉じる』ではダメだけど『ESCキーで閉じる』ならいける

『編集』 → 『設定』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/406fb698-d2c8-e728-97be-7c315613d703.png)

『一般』 → 『ESCキーでウィンドウを閉じる』。
『MDI子ウィンドウが1つしかない場合、メインウィンドウを閉じる』
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/7573bac6-e6d3-ec48-2077-1ed16d3fc8f4.png)

# 蛇足

**なにかを閉じる** という操作はCtrl + Wで統一したいけど……ままええわ。

# バージョン

Microsoft Windows [Version 10.0.19045.3803]
WinMerge Version 2.16.28.4
背景の視える化

# 背景
要求定義の際のシステム化のための本当の目的を明らかにする際、
その目的の出てきた経緯とかは暗黙知化されやすい。
また「だったらこの方法ですぐに解決できそうじゃん」っていう解がすぐに浮かんでも、
組織的な文化や内部圧力といった目に視えない要因によって、
できると思っていた選択肢が全然妥当でないなんてことがある。

その組織内の圧力含めた背景が浮き彫りになった上で、
「こんな経緯があって、だからこんな理想像を思い浮かべました。」
というように、背景＋目的のセットでないと、
最上位の目的を見失い、方針がブレブレになりやすいと感じている。

しかしながら、この背景は文章でタラタラ述べられても記憶に定着しにくい。

# 目的
要求定義の際の、トップ目的をみなが一様に具体的にイメージしやすくするために
背景をモデルで視える化することをこの記事の目的とする。
前提となる5W1Hや帰納法・演繹法などの詳細には触れない。

# やることは視える化
モデル図を使って、背景の軌跡を視える化し共有することで、
たとえ途中で方針が変更されようとも、今までにどんな経緯があって、
その上でなぜ目的が途中で変わったのか？といったことが暗黙知化されにくい。

## 因果関係と前提
物事の現象は、原因があって結果がある。
この前提のもとに背景のモデル化を進めていく。
この時、アブダクションという原因メカニズムを仮説ベースで類推する手法を用いる。
さらにその仮説の検証のために演繹法を用いる。
そのためアブダクション・演繹法を前提知識としてこの後の記事は続く。
また、あるイベントの原因になった直前のイベント、というようにイベントで背景の軌跡を表現する。

## 5W1Hで視えるか化
<img width="400" alt="スクリーンショット (299).png (70.3 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/12/26/135213/5ffaa2b2-1844-4fd4-948e-37aec8e74662.png">

5W1Hまたは、状況に応じて6W2Hで各要素を分割して
中央の起きたイベントであるコトに結びつける。
(この時、そのコトが起きた際に、値段とかが組織内で関心ではない要素であるなら、
この時点で削ってしまってOK。
ただし、そのコトに対して【誰が何をした】など重要で関心のある要素は必ず残す！)

この時、各要素はそれぞれ点要素であるのに対して、
【なぜ？】だけは点では表せられない、線としてでしか表せられない要素である。
それをこの後の平面図で表現する。

## 原因→結果というように視える化
<img width="600" alt="スクリーンショット (298).png (208.3 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/12/26/135213/06c2d899-4b8e-4095-abb6-7169187f31a5.png">

今もの前で起きた現象であるイベントと、
その原因となった直前のイベントとの因果関係モデルを作成する。
この因果関係は経験則であったり、絶対的な解ではないため、
あくまでもアブダクション手法を用いて、
「この現象が起きた理由は、あのイベントがもっとも理由として大きいと考えられる。」という仮説をベースに作成する。
ただし、実際に正しい因果関係モデルか？は検証してみて妥当性の確認を要する。

その際には、すでにある因果関係法則を一旦正しいと仮定を置き、
別の似たような事例で当てはめて検証する演繹法でチェックする。

## 上記を繰り返す
<img width="600" alt="スクリーンショット (300).png (231.6 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/12/26/135213/657d74a3-88f8-41f5-af7d-142d88892573.png">

このようにあるイベントが原因としてあったから、結果に相当するイベントが起きた
というWhyの軌跡をモデルとして視える化することで、
最上位の目的ビジョンがより骨格をハッキリとさせてくれる。

この理屈は是非ともADRの運用にも役立ててほしいと感じています。
一度定義したアーキテクチャを次のリアーキテクティング活動というイベントをする際に、
どのような理由があって、どのように変えるか？という意思決定の記録として
残すわけだから、当然過去に議論したようなアーキテクチャ決定のメカニズムを
再度議論するのは車輪の再発明をして時間を浪費してしまっている。

# 付加価値
これによって以下のことも浮き彫りにしやすいと感じる。
たとえば「なんかいっつも同じようなことに悩まされるな」ということないだろうか？
その勘は結構当たっていて、同じような悩みの事例が繰り返される。
つまりは、根本原因はいまだに解決されていないっていうことを知らせてくれている。

そんな時はちょっと面倒に感じても、上記の因果関係モデルを作成してみてほしい。

複数の事例として同じような軌跡を辿っている現象にぶち当たり続けていることが分かると思う。
(またそれを素早く気付くためにも、日ごろから起きたイベント同士の因果関係モデルを作成する文化があると望ましいかもしれないですね。)

イベントA→イベントBという因果関係の事例を事例①とします。
イベントX→イベントYという因果関係の事例を事例②とします。
イベントM→イベントNという因果関係の事例を事例③とします。
複数の事例をもとにそれらの１つ１つの現象を個別具体でみると異なる事例だけども、
共通法則を浮き彫りにするために帰納法で抽象化してみると、
どういった真因が潜んでいて、それがまだ解決されていないから、
何度も同じようなことが再発するのでは？という推測がきっと考察しやすくなります。
<img width="350" alt="共通法則.png (12.2 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/12/26/135213/9015fb8b-0aa4-433b-b648-28919ad9f66f.png">

こういった目に視えない現象メカニズムを明らかにせず、
何でもシステム化することが目的となっているとプロジェクトは失敗しやすいですね。

生産性が落ちているなと感じる際の、組織文化の再検討の時とかに必ず必須の考え方と感じますので、
規模の大きな組織になるほど、この背景の視える化を徹底してほしいなと感じています。
Flutter × FCMでpush通知(Android)実装メモ

Flutterでpush通知を実装したのですが、
モバイルアプリやFirebaseの経験がない状態だと、
関連情報が多すぎて全体像が掴みにくい印象を持ったので、開発の流れのメモです。

## ステップ1. FirebaseプロジェクトにAndroidアプリを追加する
こちらのサイトが分かりやすかったです。
週間Flutter大学：https://blog.flutteruniv.com/flutter-firebase/#toc9
リンク先の"2-7 Firebase の初期化と設定"まで進みます。

## ステップ2. FlutterにFirebaseプラグインをインストール&設定する
FirebaseプラグインをFlutterにインストールします。
これは公式の通り。
AndroidManifest.xmlのどこに書くかが分かりにくいです。chatGPTに聞くといいです。
Firebase公式：https://firebase.google.com/docs/cloud-messaging/flutter/client?hl=ja#install_the_fcm_plugin


## ステップ3. FirebaseからFlutterに通知をテストしてみる

まず、Flutter側で端末のIDを取得します。この値はテスト送信時に使います。
```dart:main.dart
final fcmToken = await FirebaseMessaging.instance.getToken();
print(fcmToken);
```
テスト送信の方法は以下のリンクを参考にしました。
Qiita: https://qiita.com/yana1316/items/9bd3806efc9cbdddcba9#firebase-cloud-messaging%E3%81%8B%E3%82%89%E3%81%AE%E9%80%81%E4%BF%A1%E3%83%86%E3%82%B9%E3%83%88

アプリをバックグラウンドにして、テストしてみるとバナーが出ると思います！

:warning:アプリがフォアグラウンドにある時に通知を送ると、バナーは出ません。
　 ので、フォアグラウンドの状態の場合は通知が来たらローカル通知を使ってバナーを出します。
https://firebase.google.com/docs/cloud-messaging/flutter/receive?hl=ja#foreground_messages
flutter_local_notificationsの使い方は...chatGPTに聞きました。
↓サンプルコード
```dart:show_notification.dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

void showNotification(RemoteMessage message) {
  const AndroidNotificationDetails androidPlatformChannelSpecifics =
      AndroidNotificationDetails(
    'your_channel_id', // チャンネルID
    'your_channel_name', // チャンネル名
    'your_channel_description', // チャンネルの説明
    importance: Importance.max,
    priority: Priority.high,
    showWhen: false,
    icon: "アイコン名",
  );
  const NotificationDetails platformChannelSpecifics =
      NotificationDetails(android: androidPlatformChannelSpecifics);
  flutterLocalNotificationsPlugin.show(
    0, // 通知ID
    message.notification!.title, // 通知のタイトル
    message.notification!.body, // 通知の本文
    platformChannelSpecifics,
  );
}
```
このshowNotification関数を通知が来たら実行するように設定します。
```dart:main.dart
// アプリが起動してる場合にメッセージが来た場合の処理
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    print("message has come");
    showNotification(message);
  });
```

これでアプリがフォアグラウンドにあっても通知が来ました！

## ステップ4. バックエンドから通知を指示する
本番ではFirebaseから手作業で送るわけには行きませんので
バックエンドから送る必要があります。

こちらの記事を参考にさせていただきました。
Qiita:https://qiita.com/nishi-sankosc/items/b9040ee57e6b7223ff21
参考：URLにプロジェクト名を入れるところだけ間違いやすいので注意です。
https://15dog.hatenablog.com/entry/2018/10/24/FCM%28Firebase_Cloud_Messaging%29_%E3%81%AE%E6%96%B0API%E3%81%AB%E7%A7%BB%E8%A1%8C%E3%81%97%E3%81%9F#:~:text=%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%20%C2%A0%7C%C2%A0%20Firebase-,%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%20%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%81%AE%E6%9B%B4%E6%96%B0,-%E5%85%A8%E7%84%B6%E3%83%8F%E3%83%9E%E3%82%8B%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88

これで、バックエンドからFirebaseを介してFlutterアプリに通知を送る、と言う流れが完成しました！
iOSに関しては機会があれば書こうと思います！
ありがとうございました:blush:
Nightbotで「グー」「チョキ」「パー」のじゃんけんをする

## グー、チョキ、パー…じゃんけん！

[Nightbotで「簡易的でない」おみくじを作る](https://qiita.com/curuusa/items/6f4d83bd0f4085ff678b)の続きです。
(「おみくじを作る」と言いながらじゃんけんしてますが)

[Nightbot](https://nightbot.tv/) のコマンドには引数が使えます。
自作したカスタムコマンドでも、もちろん引数が使えます。

今回は、Nightbotを導入したライブ配信で
「じゃんけん グー」とか「じゃんけん パー」と入力したら
その手を出してくれるコマンドを作ってみましょう。


## 引数を使ってより複雑なおみくじにする
### １． [Nightbot](https://nightbot.tv/) 側の設定
Commandos > Custom からコマンドを追加しましょう。

Messageにコマンドを入力。
新たな変数 [$(query)](https://docs.nightbot.tv/variables/query) を [$(urlfetch)](https://docs.nightbot.tv/variables/urlfetch) の前に挿入します。
(変数Zに入れています)

```javascript
$(user)の$(eval Z='$(query)';$(urlfetch json https://pastebin.com/raw/QCW1HbC5))
```
$(query) はコマンドの引数です。
「じゃんけん チョキ」の「チョキ」の部分にあたります。

### ２．[Pastebin](https://pastebin.com/) のプログラム

```javascript
/* $(query)によってモードを変える */
M=0;
if(Z=='グー' || Z=='ぐー' || Z==1){M=1;}
else if(Z=='チョキ' || Z=='ちょき' || Z==2){M=2;}
else if(Z=='パー' || Z=='ぱー' || Z==3){M=3;}
 
var X=[
[19,9,0,0,'グー!【YOU LOSE】俺の勝ち！負けは次につながるチャンスです！ネバーギブアップ！'],
[19,0,9,0,'チョキ!【YOU LOSE】俺の勝ち！たかがじゃんけん、そう思ってないですか？それやったら明日も、俺が勝ちますよ。'],
[18,0,0,8,'パー!【YOU LOSE】俺の勝ち！なんで負けたか、明日まで考えといてください。そしたら何かが見えてくるはずです。'],
[1,0,0,1,'パー!【YOU LOSE】俺の勝ち！1年間何やってたんですか？この結果はじゃんけんに対する意識の差です。'],
[1,1,0,0,'グー!!【YOU WIN】やるやん。明日は俺にリベンジさせて。'],
[1,0,1,0,'チョキ!【YOU WIN】やるやん。明日は俺にリベンジさせて。'],
[1,0,0,1,'パー!!【YOU WIN】やるやん。明日は俺にリベンジさせて。']
];
 
/* 通常で5%、指定で10%じゃんけん勝利 */
b=0;c=0;for(i=0;i<X.length;i++){b=b+X[i][M];}r=Math.floor(Math.random()*b);
for(i=0;i<X.length;i++){c=c+X[i][M];if(r<c){A=X[i][4];break;}}
```

「読みやすくなるからObject型にせい！」とか言われそうですが
すみません。今回はArray型です。

上部でモード分岐が書かれていて、
「グー」または「ぐー」なら、左から2番目の数値を使う…となってます。

### ３．ライブ配信で結果を見る
Nightbotを導入したライブ配信で
チャット欄に「じゃんけん グー」を入力すると、
しっかり「グー」だけの結果が出るはずです。

もちろん、「じゃんけん」だけでも結果が出てきます。
これで、1つのスクリプトで複数のモードがあるおみくじができました。



## 「グー」「チョキ」「パー」でじゃんけんしたい
「じゃんけん グー」「じゃんけん パー」でじゃんけんできましたが、
いちいち「じゃんけん」入れるの面倒です。私はそう思います。
[ワイトもそう思ってる](https://dic.nicovideo.jp/a/%E3%83%AF%E3%82%A4%E3%83%88%28%E3%81%91%E3%82%82%E3%81%AE%E3%83%95%E3%83%AC%E3%83%B3%E3%82%BA%29)ハズです。

なので、「グー」「チョキ」「パー」だけでもOKなコマンド設定も紹介します。


### 突然だけど、コマンド名「じゃんけん」を辞めることにした
おっと、その前に。

日本語ってひらがな・カタカナ・漢字って色んな種類ありますね。
なので、ひらがなでもカタカナでもヒットするように、
Commandも複数用意が必要です。

そして、たくさんコマンドがあると、管理が面倒くさいです。
なので、適当に作ったコマンド名「じゃんけん」をやめます。
他コマンドに合わせ「!janken」と名前を変更することにします。

「!」を付けるとコマンドっぽく見えますし、
Commandリストのソート時に１ページ目に表示されますからね。


### Aliasを使って既存のコマンドを呼び出す
[Nightbot](https://nightbot.tv/) > Commandos > Custom > +Add Command を見ると、
「Command」「Message」以外にもいくつか項目があります。

一番下にある「Alias」に、先程作ったカスタムコマンド「!janken」を入れます。
「Message」には「グー」を入れておきましょう。

すると、このCommandは「!janken グー」と入力したものと同じ結果が出ます。

「Comannd」には「グー」と入れます。
「ぐー」で同じものを作りたいときは、面倒ですがコマンドを増やしていきます。
正規表現は使えない…ハズです。

### ジャンケンには$(query)を入れる
「Alias」を使う場合、「Message」にはAliasの引数が入ります。
なので、「じゃんけん」「ジャンケン」のMessageには
変数$(query)を入れます。

これで、「!janken グー」のように、
「じゃんけん グー」「ジャンケン グー」と入力しても、
ちゃんとグーの結果が出てくるはずです。


## コマンドがいっぱい増えちゃったね
「じゃんけん」「ジャンケン」「グー」「ぐー」「チョキ」「ちょき」「パー」「ぱー」の
8種ものコマンドが必要なときでも、
「Alias」を使えば1種類のプログラムでOKということです。

えっ、それは[Nightbot Docs](https://docs.nightbot.tv/)にちゃんと書かれてるって？
英語読めるように頑張ります…。
NetlifyにNuxt3の静的サイトをデプロイする時の公開ディクレトリはdistにする

Nuxt3からNuxtを触り始めたNuxt初心者によるメモです。

## .output/publicを公開ディレクトリにするとこけてしまう

Nuxt3で静的サイトを生成するときは、`npm run generate`などのコマンドで実行ファイルを生成します。
その時の出力先として、Nuxt3のドキュメントには.outputであると書かれており、
https://nuxt.com/docs/guide/directory-structure/output

`npm run build`実行時には以下が出力されます。

![](https://storage.googleapis.com/zenn-user-upload/ad32dc985410-20231226.png)

ではNetlifyの公開ディレクトリも `.outpu/public`に設定すればいいのかと思ったのですが、
![](https://storage.googleapis.com/zenn-user-upload/8da281e5c949-20231226.png)

Deploy directory ".output/public" does not existというエラーでこけてしまう...
![](https://storage.googleapis.com/zenn-user-upload/633f246cebd5-20231226.png)

## .output/publicへのシンボリックリンクとして設定されているdistディレクトリ

Nuxt2では、静的ファイルはdistディレクトリに格納される。
`.output`以下に静的ファイルが格納されるようになったのはNuxt3から。

いろいろ調べたのをまとめると、Nuxt 3プロジェクトでは、ビルドプロセスが.output/publicディレクトリを生成し、それと同時に同時に、互換性のために`dist`ディレクトリは`.output/public`へのシンボリックリンクとして設定され、Nuxt2以前のツールや設定との互換を保つ感じのようです。

https://qiita.com/ayumun_jp/items/bf7ff6d0002c4b48c5a9
https://v2.nuxt.com/ja/docs/directory-structure/dist/

## Netlifyでの公開ディクレトリをdistにしたらうまく行った

タイトルの通りです。
公開ディレクトリを`.output/public`から`dist`に変更したらうまくいきました。

![](https://storage.googleapis.com/zenn-user-upload/57726e57b31f-20231226.png)


実体である`.output/public`の設定でエラーになってしまうのはなぜか今のところわからずですが、netlifyでNuxt3の静的サイトを公開するときのディレクトリは`dist`にしておくのが良さそうです。。
コミュニケーションにおけるPrefixの重要性(意味を絞るということ)

## 質問や議論をする際につけるPrefix

```
確認
相談
報告
意図
仮定
推測
解釈
事実
提案
意見
注意
懸念
認識
以前、現在、今後(過去や未来について)
前提の共有
この会の目的は
背景・経緯
具体例
補足
メリット
デメリット
転用
途中経過の共有・進捗の共有
この会では3つの議題があります。
```

よく使います。

メリットは以下の通り。

- 相手の頭の中に「これからどんな話をするか、会話の方向性」を伝えられるので、相手の思考リソースを割かせない。
- Prefixで絞ることで、相手に発言の意図を伝えられるため、議論の際にこちらの提案に悪意がないことを伝えられる。これは、不要な反発を防ぐことができる上に、長期的に良好な人間関係を構築することができて便利。



## 文章・口語の中で日本語を扱う

前提を共有する
- 主語を明確にする
- こそあど言葉を使わない([「これ・それ・あれ・どれ」](https://altenas.jp/blog/about-demonstrative-pronouns)など)
- 相手の理解度を都度確認する(ここまで大丈夫ですか？など)
- 先述の「質問や議論をする際につけるPrefix」で記載したメタ概念を都度使う

基本的に自分の常識と相手の常識は違うので、そこの認識合わせを行うつもりで。


## レビュー
MUST,IMO,NITS

### MUST
- 日本語訳で「〜しなければならない」
- これコード動かないんじゃね？系を記載(こっちが多め)
- レビューコメントを残すにあたり、相手のコードのA案より、自分の修正案がB案の方が技術的に適切である明確な理由を説明できる場合に使うことが多いです。(ただ、大体の場合宗派があるので、この文の動機で使用する場合は新入社員や未経験エンジニアなどに限られるかも？よって、あまり出番はない。)
- 設計ミスってる時もMUSTになりますが、その場合そもそもMUSTの次元ではなく、手戻りなので、大きいタスクを行う際は小さく相談フェーズを挟むといいかもです。

### IMO
- in my opinionで、日本語訳で「私の意見では」
- 個人的にはよく使います
- 「正直どっちでも動くけど、多分こっちのがいいんじゃね？」みたいな、私の主観的目線で、80点のコードを85点に、50点のコードを55点に変更する依頼をする場合に重宝してます。
- IMOをなくすと、「こう変更すべきだ。お前は間違ってる」という人格否定のニュアンスで相手がレビューを受け取る恐れがあります。
- レビューを受ける側のメンタルモデルとして「成果物と個人の人格を分離する」ことが重要ですが、できる人はそう多くありません。特に日本人は幼少期にディベートの経験が少ないことから、議論での結果を人格の評価と結びつけがちです。
- 自分がレビューを受ける時は成果物と個人の人格を分離するよう努めていますが、「他人がそうとは限らない。よって相手のメンタルモデル次第では長期的な人間関係に影響する」ので、なるべくIMOはつけてレビューするようにしています。

### NITS
- nitpickで「些細な指摘（重箱の隅をつつくの意味）」
- 相手の不意のミスや当たり前のことについて提案の意味を込めて使うことが多いです。NITSに限らずですが、基本的に下から謙遜ムーブでレビューコメントをすることが多いです。
- NITS的な指摘をする場合、prefixなしで指摘をすると「こんな当たり前なことできてないの？」というニュアンスを含んでしまいます。これは知性への脅しになります。エンジニアはやりがちですが、これは長期的な人間関係に影響するかと思います。

### WANT
- 「私は〜したい」なので、要望を表す
- 提案ベース、僭越ながら相手に依頼をお願いしてもいいですか？のような文脈で使用
- 相手の成果物は100%であることを前提に、面倒なことを追加で実装いただく際に使用
- こちらが下から謙りつつ相手に提案ができるため便利。相手のプライドを毀損しない。
Laravel: MiddleWare の使い方

<ol>

<li>プロジェクトの作成</li>

```bash
laravel new grimm
```

<li>routes/web.php の編集</li>

```php:routes/web.php
（省略）
（最後に加える）
Route::get('grimm','App\Http\Controllers\GrimmController@index')
        ->middleware(App\Http\Middleware\GrimmMiddleware::class);
```

<li>Controller の作成</li>

```bash
php artisan make:controller GrimmController
```

>app/Http/Controllers/GrimmController.php が出来ます。


<li>MiddleWare の作成</li>

```bash
php artisan make:middleware GrimmMiddleware
```

>app/Http/Middleware/GrimmMiddleware.php が出来ます。

<li>Route の確認</li>

```bash
php artisan route:list
```

```text
$ php artisan route:list

  GET|HEAD   / ............................................................... 
  POST       _ignition/execute-solution ignition.executeSolution › Spatie\Lar…
  GET|HEAD   _ignition/health-check ignition.healthCheck › Spatie\LaravelIgni…
  POST       _ignition/update-config ignition.updateConfig › Spatie\LaravelIg…
  GET|HEAD   api/user ........................................................ 
  GET|HEAD   grimm ..................................... GrimmController@index
  GET|HEAD   sanctum/csrf-cookie sanctum.csrf-cookie › Laravel\Sanctum › Csrf…
```

<li>app/Http/Controllers/GrimmController.php の編集</li>

```php:app/Http/Controllers/GrimmController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class GrimmController extends Controller
{
	public function index(Request $request)
	{
	error_log('*** GrimmController index ***');
	error_log(var_export($request->data,true));

	return view('grimm.index',['data'=>$request->data]);
	}

}
```

<li>app/Http/Middleware/GrimmMiddleware.php の編集</li>

```php:app/Http/Middleware/GrimmMiddleware.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class GrimmMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
   
	    $data = [
		    ['khm'=>'12','title'=>'ラプンツェル'],
		    ['khm'=>'24','title'=>'ホレおばさん'],
		    ['khm'=>'27','title'=>'ブレーメンの音楽隊'],
		    ['khm'=>'50','title'=>'いばらひめ'],
	    ];

	    $request->merge(['data'=>$data]);

        return $next($request);
    }
}
```

<li>resources/views/grimm/index.blade.php の作成</li>

```bash
mkdir resources/views/grimm
```

```php:resources/views/grimm/index.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>グリムの昔話</title>
</head>
<body>
<h2>グリムの昔話</h2>
@section('content')
<p>良く知られている話</p>
<table>
@foreach($data as $item)
<tr><th>{{$item['khm']}}</th><td>{{$item['title']}}</td></tr>
@endforeach
</table>
@show
<p>Dec/26/2023</p>
</body>
</html>
```

<li>サーバーの起動</li>

```bash
php artisan serve
```

<li>ブラウザーで、　http://localhost:8000/grimm　にアクセス</li>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f71a693b-fa65-355c-1f3e-81bfddc90efb.png)

</ol>
OCI HPC Cluster: トラブルシューティング - MPI関連

:::note info
本ページは [OCI: HPC Cluster](https://qiita.com/itokazu/items/63d2e3cebdcdda5afce0) のサブページになります。
:::

# MPI 関連
### Q: Intel MPI v2021.x でアプリを実行するとハングする
Intel MPI v2021.x で以下のオプションで実行した場合、アプリがハングするケーズがございます。

```
-iface ens800f0 -genv UCX_TLS=rc,self,sm -genv UCX_NET_DEVICES=mlx5_2:1 -genv I_MPI_FABRICS=shm:ofi
```

その場合、`I_MPI_FABRICS=shm:ofi` を `I_MPI_FABRICS=ofi` に変更して実行をお願いします。
OCI HPC Cluster: FAQ - その他

:::note info
本ページは [OCI: HPC Cluster](https://qiita.com/itokazu/items/63d2e3cebdcdda5afce0) のサブページになります。
:::

## その他

### Q: インターネット接続でセキュアに利用するために注意すべきポイントは？
A: 以下のポイントにご注意ください
- SSH でパスワード認証を使わない(デフォルトは鍵認証)
- VNCのSecurity Listで接続元のIPを絞る

### Q: 計算ノード間で RDMA 通信がされていることは確認可能か？
A: 可能です。

以下の手順でスクリプトをダウンロードし、ジョブ実行中に dump_mlx_preiodic.sh を実行してください。
送受信のデータサイズとパケット数が確認可能です。

本スクリプトでは指定した NIC の統計情報を出力するもので TCP/IP だけでなく RDMA も含まれます。
逆に netstat -i の結果には RDMA 通信は含まれません。
本スクリプトと netstat -i の両方を確認することで RDMA 通信をしているか判断できます。
 
また、 このスクリプトは計算ノードに負荷が掛かるのでご注意ください。

ターミナルを2つ用意し、一つは以下のスクリプトを実行し、もう一つでは `netstat -i 1 | grep <Interface名>` を実行し、その状態でアプリケーションを実施してください。Interface 名は、BM．Optimized3.36 が `ens800f0` で BM．HPC2．36 が `enp94s0f0` になります。
netstat のカウンタが変化せず、dump_mlx_periodic.sh スクリプトがカウントされれば RDMA 通信が行われていることが確認できます。

```
$ ssh <計算ノード>
$ git clone https://github.com/kazuitox/oci-hpc-tools.git
$ cd oci-hpc-tools/bin

# BM.Optimized3.36 の場合
$ ./dump_mlx_periodic.sh 1 mlx5_2
2022年 2月 19日 土曜日 08:34:26 GMT: recv_data=25378781, recv_packets=103318, xmit_data=23817383, xmit_packets=100877
2022年 2月 19日 土曜日 08:34:27 GMT: recv_data=26281714, recv_packets=76186, xmit_data=32492127, xmit_packets=90459
2022年 2月 19日 土曜日 08:34:28 GMT: recv_data=29166371, recv_packets=127388, xmit_data=29066583, xmit_packets=122254
^C

# BM.HPC2.36 の場合
$ ./dump_mlx_periodic.sh 1 mlx5_0
```
recv_data, xmit_data の単位は byte で、recv_packets, xmit_packets はパケット数になります。

### Q: ログインノードのホスト名を変更することは可能ですか？
技術的には可能ですが、推奨はしていません。
ログインノード上で動いているサービス(SLURM, LDAPなど)の設定ファイルにログインノードのホスト名が直接書かれており、それらの変更と動作確認が必要になります。
Windows で大きいサイズのファイルを作る方法

Windows で大きいサイズのファイルを作る方法
//10GBのファイルを作成
fsutil file createnew testfile.txt 10737418240


参考
【Windows 11対応】巨大サイズのファイルをfsutilコマンドで簡単に作る
https://atmarkit.itmedia.co.jp/ait/articles/0209/28/news002.html
OCI HPC Cluster: FAQ - MPI関連

:::note info
本ページは [OCI: HPC Cluster](https://qiita.com/itokazu/items/63d2e3cebdcdda5afce0) のサブページになります。
:::


## MPI 関連
### Q: MPI はプリインストールされているか？
OpenMPI ver.4 と Intel MPI (OneAPI)がプリインストールされています。
OpemMPI は `/usr/mpi` 配下、Intel MPI は `/opt/intel`配下にインストールされています。

### Q: MPI で RDMA を利用するためにはどんなオプションを指定すれば良いか？
OCI では RDMA の I/F として RoCEv2 を採用しております。代表的な以下3つの MPI で RoCEv2 を利用するオプションを記載します。インスタンスや MPI の ver によりオプションが異なるのでご注意ください。

#### OpenMPI 3.x
- BM.HPC2.36:

```
-mca btl self -x UCX_TLS=rc,self,sm -x HCOLL_ENABLE_MCAST_ALL=0 -mca coll_hcoll_enable 0 -x UCX_IB_TRAFFIC_CLASS=105 -x UCX_IB_GID_INDEX=3
```

#### OpenMPI 4.x 
- BM.HPC2.36:
```
-mca pml ucx -x UCX_NET_DEVICES=mlx5_0:1 -mca coll_hcoll_enable 0 -x UCX_IB_TRAFFIC_CLASS=105 -x UCX_IB_GID_INDEX=3 -x HCOLL_ENABLE_MCAST_ALL=0
```

- BM.Optimized3.36:
```
-mca pml ucx -x UCX_NET_DEVICES=mlx5_2:1 -mca coll_hcoll_enable 0 -x UCX_IB_TRAFFIC_CLASS=105 -x UCX_IB_GID_INDEX=3 -x HCOLL_ENABLE_MCAST_ALL=0
```

#### Intel MPI 2018 まで
- BM.HPC2.36:
```
-iface enp94s0f0 -genv I_MPI_FABRICS=shm:dapl -genv DAT_OVERRIDE=/etc/dat.conf -genv I_MPI_DAT_LIBRARY=/usr/lib64/libdat2.so -genv I_MPI_DAPL_PROVIDER=ofa-v2-cma-roe-enp94s0f0 -genv I_MPI_FALLBACK=0
```

BM.Optimized3.36:
```
-iface ens800f0 -genv I_MPI_FABRICS=shm:dapl -genv DAT_OVERRIDE=/etc/dat.conf -genv I_MPI_DAT_LIBRARY=/usr/lib64/libdat2.so -genv I_MPI_DAPL_PROVIDER=ofa-v2-cma-roe-ens800f0 -genv I_MPI_FALLBACK=0
```

#### Intel MPI 2019 から
- BM.HPC2.36:
```
-iface enp94s0f0 -genv I_MPI_FABRICS=shm:ofi
```

- BM.Optimized3.36 + Oracle Linux7:
```
-iface ens800f0 -genv UCX_TLS=rc,self,sm -genv UCX_NET_DEVICES=mlx5_2:1 -genv I_MPI_FABRICS=shm:ofi
```

- BM.Optimized3.36 + Oracle Linux8:
```
-iface rdma -genv UCX_TLS=rc,self,sm -genv UCX_NET_DEVICES=mlx5_2:1 -genv I_MPI_FABRICS=shm:ofi
```

#### Platform MPI
- BM.HPC2.36:
```
-intra=shm -e MPI_HASIC_UDAPL=ofa-v2-cma-roe-enp94s0f0 -UDAPL -e MPI_FLAGS=y
```

- BM.Optimized3.36:

```
-intra=shm -e MPI_HASIC_UDAPL=ofa-v2-cma-roe-ens800f0 -UDAPL -e MPI_FLAGS=y
```

### Q: VM Shapeにて複数ノードでジョブを実行したい
VM Shapeの場合、ノード間通信はTCPを利用することになります(RDMAはBM Shapeのみ対応のため)。
また2024年3月27日現在、HPC Clusterで生成されるVM ShapeではHyperthredingを無効にできないため、それについても対処をする必要があります。

#### OpenMPI v4
ポイント
- tcpを明示的に指定: --mca btl self,tcp
- HCOLLを明示的に無効: --mca coll_hcoll_enable 0
- 物理コアへのバインド: --bind-to core 
```
--mca btl self,tcp --mca coll_hcoll_enable 0 --bind-to core
```
【JavaScript】オブジェクトの特徴について

JavaScriptの仕様でオブジェクトは参照渡しというものがあります。

Reactのドキュメントを読んでいたところオブジェクトのコピーについて理解できてなかったのでこの際に理解を深めたいと思います。

https://ja.react.dev/learn/updating-objects-in-state

## JavaScripの参照渡しについて

JavaScriptでは、プリミティブ型の数値、文字列、真偽値、null、undefinedなどは値渡しですが、**オブジェクト型の配列、連想配列、関数は参照渡し**です。


## なぜ参照渡しなのか？
JavaScriptのメモリ管理とパフォーマンスに考慮するためだそうです。

具体的には、プリミティブ型は値が直接保存されるため、その値をコピーする際には新しいメモリ領域を確保して値をコピーする必要があります。

一方、オブジェクト型は参照渡しなのオブジェクトが保存されているメモリ領域への参照をコピーすることでメモリ使用量は少なくなります。

:::note alert
オブジェクトのプロパティを変更した場合、その変更は参照を持っているすべての変数に反映されます。
オブジェクトのデータ量に応じて処理に負荷がかかるため値の変更に注意が必要です。
:::

まとめると…
- 値渡しは、メモリ使用量が増えるが変更の際のパフォーマンスは良い
- 参照渡しは、メモリの使用量は減るが変更の際のパフォーマンスに注意が必要

:::note info
小さなデータを扱う場合は値渡しの方が効率的、大きなデータの場合は値渡しの方が効率的。
:::

## そもそもJavaScriptに「参照渡し」は存在しない！？
この記事では「参照渡し」として諸所説明してきましたが…そもそもJavaScriptに「参照渡し」はないと知りました。

:::note info
コメントでもいただいている通り、JavaScriptにおける「参照渡し」は**参照の値渡し**という表現が正しいようです。
:::

**参照渡し**と**参照の値渡し**をコードで説明すると

```javascript
let a = { value: 10 }
let b = a

a.value = 50
console.log(a) // { value: 50 }
console.log(b) // { value: 50 }
```

`a`の`value`を変更すると`b`の値も連動して変化します。
これが**参照渡し**と言われる状態です。

ただ、下記のようにすると`a`と`b`の値がそれぞれ別のものになります。

```javascript
let a = { value: 10 }
let b = a

a = { value: 50 }
console.log(a) // { value: 50 }
console.log(b) // { value: 10 }
```

**参照渡し**であれば`a`が置き換わると`b`も置き換わっているはずですが、JavaScriptの場合は別の値に置き換わってしまって連動しなくなります。

:::note warn
なのでJavaScriptの**参照渡し**と言われているものは、世間一般の参照渡しとは性質の異なるものです。
:::

実際には「参照値」という「値」を「値渡し」しているため**参照の値渡し**と表現されるそうです。

### 参考の記事

https://qiita.com/ur_kinsk/items/949dabe975bdc1affb82

https://qiita.com/yuta0801/items/f8690a6e129c594de5fb

https://qiita.com/sakaimo/items/51eb797b0937713017e2

https://qiita.com/Yametaro/items/21f7b1a4ae09f16f323e

https://qiita.com/Yametaro/items/45dbfd7f544a69ea7b36

https://e-words.jp/w/%E5%8F%82%E7%85%A7%E6%B8%A1%E3%81%97.html

https://e-words.jp/w/%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E6%B8%A1%E3%81%97.html

## まとめ
オブジェクトの特徴について考えたことはなかったですが、JavaScriptの仕様に詳しくなればコードを綺麗に書くことに繋がったり、デバッグの速度が上がったりするのではないかと思います。

とはいえ量が多いので、1つずつ深度を深めてJavaScriptへの理解を深めいたいと思います。
闘魂Elixir ── Advent of code 2023 Day 4 Part 1 を Livebook で楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>

https://qiita.com/advent-calendar/2023/elixir

## はじめに

@torifukukaiou さんの ~~パク~~ リスペクト記事です

https://qiita.com/torifukukaiou/items/ece3f4bc2948ca4ac7e4

Elixir Livebook で Advent of Code 2023 の問題を解いてみます

https://adventofcode.com/2023

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2023/2023_day4_part1.livemd

問題はこちら

https://adventofcode.com/2023/day/4

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1.5"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

Day 4 の入力を取得します

![スクリーンショット 2023-12-26 13.10.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/1cde497d-a54f-f56e-b8b2-bc14d20fb936.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>details</summary>

回答用のモジュールです

入力を扱いやすい形にするための `parse` と、回答を作るための `resolve` 関数を持っています

```elixir
defmodule Resolver do
  def parse(input) do
    input
    |> String.split("\n")
    |> Enum.map(fn line ->
      [_, card] = String.split(line, ":")
      [winning_card, my_card] = String.split(card, "|")

      %{
        winning_card: parse_card(winning_card),
        my_card: parse_card(my_card)
      }
    end)
  end

  defp parse_card(card) do
    card
    |> String.split(" ")
    |> Enum.filter(fn value -> value != "" end)
    |> Enum.map(fn value -> String.to_integer(value) end)
  end

  def resolve(games) do
    games
    |> Enum.map(fn %{winning_card: winning_card, my_card: my_card} ->
      winning_card
      |> Enum.count(fn winnig_number ->
        Enum.member?(my_card, winnig_number)
      end)
      |> get_point()
    end)
    |> Enum.sum()
  end

  defp get_point(0), do: 0
  defp get_point(1), do: 1
  defp get_point(nuber_of_matches) do
    0..(nuber_of_matches - 2)
    |> Enum.map(&Integer.pow(2, &1))
    |> Enum.sum()
    |> Kernel.+(1)
  end
end
```

`parse` では、数字をスペース区切りした後、空文字を除いてカードの数字を読み取っています

```elixir
defp parse_card(card) do
  card
  |> String.split(" ")
  |> Enum.filter(fn value -> value != "" end)
  |> Enum.map(fn value -> String.to_integer(value) end)
end
```

`resolve` では `Enum.member?` を使うことで、当選番号が自分のカードに含まれているかを検査しています

`get_point` 関数でマッチした数をポイントに変換します

```elixir
defp get_point(0), do: 0
defp get_point(1), do: 1
defp get_point(nuber_of_matches) do
  0..(nuber_of_matches - 2)
  |> Enum.map(&Integer.pow(2, &1))
  |> Enum.sum()
  |> Kernel.+(1)
end
```

ポイントはマッチ数が 0 のとき 0、 1 のとき 1 で、それ以上では以下の数式で表されます

$$
p = 1 + \sum_{k=0}^{m-2}2^k
$$

(p: ポイント、 m: マッチ数)

</details>

## まとめ

ポイントの説明が分かりにくかったので最初戸惑いましたが、理解できれば実装は単純ですね

Part 2 はこちら

https://qiita.com/RyoWakabayashi/items/2a541a0fa91cb630a33a
[Memo]単体テスト項目注意点(随時更新)

## 全体
- **InputとOutputを意識する。途中デバッグで確認する項目は基本必要がない**
- 文言統一、する/しない、または　される/されない
- 同一項目、複数パターンをテストする場合、マトリックスにする
- 分岐処理で、先に正常ルートの一連処理、そのあとは異常ルートの一連処理
(見やすいし、テストしやすい)
- 項目をすべて作成後、動きを確認しながら、項目漏れかを確認する
- サブ項目なら、字下げ

## 画面処理
- 画面に存在する項目(テキストボックス、ラベルなど)について、「画面仕様書通りになること」でよい
-- 例：
-- 下記項目が画面仕様書通りになっていること
-- 1. タイトル
-- 2. レイアウト
-- 3. タブの移動順序
-- 4. ...
- メッセージボックスに対して、タイトル/メッセージ/アイコン/ボタン なども確認する

## 内部処理
- 未記載
Django - ローカル開発環境構からテンプレート表示まで

# 環境構築
```bash:terminal
python3 -m venv venv

source venv/bin/activate

python -m pip install --upgrade pip

pip install django

pip freeze > requirements.txt

django-admin startproject core .

python manage.py startapp website

```

# 設定ファイルの編集
```python:settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'website'
]

TIME_ZONE = 'Asia/Tokyo'

LANGUAGE_CODE = 'ja'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'sample',
        'USER': 'root',
        'PASSWORD': '',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

```

#  MySQLを使用
```bash:terminal
pip install mysqlclient

mysql.server start

mysql -uroot 
```

# DBの作成
```sql:mysql
create database sample;
```

# マイグレーションとスーパーユーザー作成
```bash:terminal
python manage.py makemigrations

python manage.py migrate  

python manage.py createsuperuser
```

# URL、views、template設定
```python:core/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', include('website.urls')),
    path('admin/', admin.site.urls),
]
```

```python:website/urls.py
from django.urls import path
from .views import index

urlpatterns = [
    path('', index, name='index'),
]
```

```python:website/views.py
from django.shortcuts import render

def index(request):
    return render(request, 'website/index.html', {})
```

```html:website/templates/website/index.html
<html>
    hello world
</html>
```