OmniAICreator/Qiita-1.07M huggingface dataset:
PowerQueryとSalesforce

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)


+ [Microsoft Power BI との連携](https://qiita.com/Keiji_otsubo/items/1f5943cfff188aa5c06f)


+ [Excel PowerQuery でオブジェクトを取得した際に項目の表示ラベルを表示したい](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000PeMJfSAN)

:::note
どうも出来ないというような回答がされています。

https://community.powerbi.com/t5/Desktop/Can-you-pull-Salesforce-field-labels/td-p/2127536
:::


+ [SalesforceのレポートとPowerBI Desktopでの自動化](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007CJ9Zn)

:::note
リアルタイム連携については、有償のツールがあるみたいです。

Power BI Salesforce Connector - Sales forcePower BI Connectors
https://www.googleadservices.com/pagead/aclk?sa=L&ai=DChcSEwjH2-jvx8yAAxXs2BYFHXICDGMYABACGgJ0bA&gclid=Cj0KCQjwz8emBhDrARIsANNJjS4Lor0nm-fxWQ8cNZIMvA62bkM9OXpOzY3B1WUouz0WQ1MXxPbg5YEaAkm1EALw_wcB&ohost=www.google.com&cid=CAESauD2-bNJznBRVdhYvzntQbGm_HYlYy2SEcYAHsNvYh7LPdCuV8JkpNu3weWLVA8LDd4_hgQGuaYJMR9ZoijwQnoAEzFQt1FQ9Wgc2G4m1cBzf6enNJubm29hU1Y1hsASsqIPPjeRtzPeT44&sig=AOD64_3_FRQylzKpR5E-01epXm6OuV6j9g&q&adurl&ved=2ahUKEwjG7ODvx8yAAxXvavUHHbtsC24Q0Qx6BAgMEAE
:::
RSA SecureID

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)


+ [SecurID トークン](http://www.techmatrix.co.jp/product/securid/token/index.html)

SecurID ハードトークンは、時刻同期方式のワンタイムパスワードを生成する認証デバイスです。 トークンに表示される 60 秒毎に変わるトークンと、カードの所有者を示す PIN 番号 (暗証番号)を組み合わせて、その時の自分のパスワードとして使用します。
一度認証に使用したパスワードは、再利用が出来ませんので、 万全のセキュリティを確保することが出来ます。
専用のカードリーダは不要です。


+ [RSA SecureID をセットアップする](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000JgD7aSAF)

:::note
Please check this article.

Salesforce - RSA Ready SecurID Access Implementation Guid
https://community.rsa.com/t5/securid-integrations/salesforce-rsa-ready-securid-access-implementation-guide/ta-p/569859
:::
Glue StudioでTPC-DSデータセットをインポートする

# はじめに

TPCはデータベースの性能ベンチマークに使われるデータセットやクエリを定義しているものになります。特に[TPC-DS](https://www.tpc.org/tpcds/)はビッグデータ関連のベンチマークで使われることがあり、GlueやAthenaの性能を測定するのに有用です。
Glueには[コネクタ](https://docs.aws.amazon.com/ja_jp/glue/latest/ug/connectors-chapter.html#using-connectors-overview)と呼ばれる、外部のデータソースに接続する機能がありAWS Marketplaceで様々なコネクタが提供されています。
AWS MarketplaceにTPC-DSデータセットをインポートするためのコネクタも用意されており、こちらとGlue Studioを使用することでノンコーディングでAWS環境にTPC-DSデータセットを作成することができます。

# 使い方

## TPC-DSコネクタのインストール

まずは、AWS MarketplaceからTPC-DSコネクタを取得する必要があります。
マネジメントコンソールでGlueの画面に遷移し、 `Data connections` → `Go to AWS Marketplace`を選択します。

![スクリーンショット 2023-04-19 11.12.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276167/f47bf949-fade-d06a-8182-e4dcbf3b3b00.png)

次に検索窓に `tpc-ds` と入力するとTPC-DSコネクタが表示されるので、それを選択します。その後は画面に従って進むことでTPC-DSコネクタのインストールができます。

![スクリーンショット 2023-04-19 11.12.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276167/2be26c9f-b209-33da-5127-7461be478d00.png)

## Glue Studioでのジョブ作成

インストールしたTPC-DSコネクタはGlue StudioのVisual画面等から利用可能になります。ここではGlue StudioでTPC-DSコネクタから取得したデータセットをS3に出力するジョブを作成します。

- まずは、Glue StudioのVisual画面で `Data` → `TPC-DS connector`を選択します。

![スクリーンショット 2023-04-19 11.15.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276167/8b8654e1-b926-fb4b-da62-a3e2607f1de9.png)

- TPC-DS connectorの `Data source properties - Connector`の`Connection options`には以下の項目を設定します。

| Key | Value | 内容          |
|:-----------|:------------|:-------------|
| scale       | 1以上の数値        |  作成するデータの規模。詳細は参考に記載のTPC-DSの仕様についてを参照ください。 |
| table     | TPC-DSのテーブル名      | インポートするTPC-DSで定義されているテーブル名を指定。テーブルの詳細は参考に記載のTPC-DSの仕様についてを参照ください。       |
| numPartitions       | 1以上の数値        | Sparkのパーティション数。         |

![スクリーンショット 2023-04-19 11.34.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276167/7d46cdcc-1180-c7de-bd7f-74aec90073f3.png)

- TPC-DS connectorの設定が終わったら、TargetとしてAmazon S3を選択して、データの出力パス等の設定をします。
- `Job details`の設定をした後、ジョブを実行すると以下のようにS3にデータが出力されます。TPC-DS connectorで設定した `numPartitions`はSparkのパーティション数で内部の並列処理の単位になりますが、特にデータ加工等せずTPC-DS connectorで取得したデータをそのままS3に出力する場合は、`numPartitions`で指定した数と同じオブジェクトがS3に出力されます。(下の画像だと `numPartitions` = 100で指定）

![スクリーンショット 2023-04-21 8.04.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276167/55c4a051-f816-2d67-53cb-ad02e2133341.png)

# まとめ

このようにTPC-DS connectorおよびGlue Studioを使用することでノンコーディングでS3にTPC-DSのデータセットをインポートすることができました。
また、AWS Marketplaceにはその他にも様々なコネクタが用意されているので、今回TPC-DSデータセットをインポートしたのと同じような手順で様々なデータをGlueに取り込むことができます。


# 参考

TPC-DSの仕様について: https://www.tpc.org/tpc_documents_current_versions/pdf/tpc-ds_v2.7.0.pdf
ググりづらいkotlin構文たち


随時更新予定。

# `: () -> Unit`　

変数や関数に型を指定しています。
**`: () -> Unit型の変数`　＝　`処理だけが入っている変数`** と考えていいと思います。

`Unit`は`void`のように、`返す値が無い事`を表します。
`返す値が無い事`を型に指定する　とはどういう事か、イメージしづらいと思います。<br>
kotlinは関数を変数に格納できるので、<br>格納しても中身には`処理`だけが入っていて、`実物`が無い。みたいなイメージです。


[AndroidDeveloper codelab](https://developer.android.com/codelabs/basic-android-kotlin-compose-function-types-and-lambda#3)


### おまけ
Androidやkotlinについては分野ごとに[AndroidDeveloper Codelab](https://developer.android.com/codelabs)　というわかりやすい上に練習もさせてくれる公式ページがあり、Androidだけでなくkotlinの勉強も１からやらせてくれます。
本来そちらを順番にこなしていくのがいいのですが、この記事はそんな時間が無い方向けです。
【Java初心者用】標準出力まとめ


# 目次
[標準入出力について](#標準入出力について)
[標準出力](#標準出力)
[おわりに](#おわりに)
[参考文献](#参考文献)




# 標準入出力について
ターミナルに直接文字を打ち込んだり、表示させたりするときにするときに利用する。
業務だったら顧客が打ち込んだ住所などを受け取ったりするのに必要であるし、
普段だったら競技プログラミングで使用する（Javaでやる人は小数だと思うが）。


# 標準出力
観てみたほうが早いのでとりあえずサンプルコードを以下に示す。
```java:Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("このように表示されます");
    }
}
```

```terminal:実行結果
このように表示されます
```

大切なのは **System.out.println()** である。ここに表示したい文章を入れればそれでOK！
プログラム内に変数があって(例えば年齢など)、それも一緒に表示したいときは+でくっつければよい。
```java:Main.java
public class Main {
    public static void main(String[] args) {
        int age = 20;
        System.out.println("私は" + age + "歳です");
    }
}
```

```terminal:実行結果
私は20歳です
```

他にも改行させたくなかったり、pythonのf文字列的な表記方法もある。
以下には代表的なメソッド、挙動、使用例を示す。

| メソッド | 挙動 |
| :-- | :-: |
| [println](#printlnメソッド) | １行ずつ表示するとき |
| [print](#printメソッド) | 改行させたくないとき |
| [printf](#printfメソッド) | 数字や文字列の結合をもっと簡単にしたいとき |

## printlnメソッド
```java:Main.java
public class Main {
    public static void main(String[] args) {
        int age = 20;
        System.out.println("こんにちは。");
        System.out.println("私は" + age + "歳です。");
    }
}
```

```terminal:実行結果
こんにちは。
私は20歳です。
```
## printメソッド
```java:Main.java
public class Main {
    public static void main(String[] args) {
        System.out.print("こんにちは。");
        System.out.print("改行できません。");
        System.out.print("しかし、\nこうすると\n改行できます。");
    }
}
```

```terminal:実行結果
こんにちは。改行できません。しかし、
こうすると
改行できます。
```

## printfメソッド
```java:Main.java
public class Main {
    public static void main(String[] args) {
        int age1 = 1;
        int days =365;
        int age2 = 2;
        String laugh = "ふふふ";
        System.out.printf("私は%d歳です。",age1);
        System.out.printf("しかし、\nあと%d日寝ると、%d歳になります。%s", days, age2, laugh);
    }
}
```

```terminal:実行結果
私は1歳です。しかし、
あと365日寝ると、2歳になります。ふふふ
```
このprintfメソッドは少しめんどくさい部分もある。
受け取る変数型によって文字列に埋め込む記号が変わるのだ。
以下に表でまとめた。
| 記号 | 説明 | 使用例 | 結果 |
| :-- | :-: | :--:| --:|
| %s | 文字列 | System.out.printf("%s","あい") | あい |
| %d | 整数 | System.out.printf("あ%d",12) | あ12 |
| %数d | 最小桁数を指定| System.out.printf("あ%3d",12) | あ 12 |
| %f | 浮動小数 | System.out.printf("%f",3.1415) | 3.1415 |
| %.数f | 小数点以下を指定| System.out.printf("%.2f",3.1415) | 3.14 |

他にもprintfには細かい仕様があるようだ。
[こちらの記事](https://qiita.com/takahirocook/items/06d525be63eccd99ed49)によくまとまっている。


# おわりに
この記事を書いている私自身、Javaのことはかなりちんぷんかんである。
したがって間違っていたり不適切な表現があるかもしれないが（絶対ある）、
その際はコメントでも残してくれると非常にありがたい。

そういえば競技プログラミングでよく用いられる半角スペース区切りで出力はよくわからなかった。

# 参考文献
* [【Java】printf()メソッド (任意のフォーマットで文字を出力)](https://qiita.com/takahirocook/items/06d525be63eccd99ed49)
日本語に不慣れなchatGPTを励ました時の話

Q:以下が私からの質問、A:以下がchatGPTからの答えを示します。この時点のchatGPTのバージョンは2023/3/23です。

Q:
しりとりをしましょう。ではわたしから。「かっぱ」

A:
ありがとうございます。では、「ぱんだ」でいきます。

Q:
「だんち」

A:
「ちゅうりっぷ」でいきます。

Q:
「プロフェッショナル」

A:
「あんず」でいきます。

Q:
間違ってますよ。「る」から始まる言葉でないと。

A:
申し訳ありません。「る」から始まる言葉を考えます。「るすばん」でいきます。

Q:
それもダメです。「ん」で終わる言葉を言うと負けになってしまいますよ。

A:
すみません、初歩的なミスを犯しました。では、「るり色」でいきます。

Q:
「ロックンロール」

A:
「るす」といきたいところですが、やはりそれはダメですね。では、「ろうそく」でいきます。

Q:
「るす」はセーフですよ。「る」で始まる言葉ですから「ろうそく」は間違いです。

A:
ありがとうございます。では「るす」でいきます。

Q:
「スイカ」

A:
「かばん」でいきます。

Q:
「ん」で終わる言葉はダメだと言ったじゃないですか。しりとりは苦手ですか？

A:
すみません、また初歩的なミスを犯してしまいました。しりとりは得意なはずなのですが、ミスがあるとは情けない限りです。次は「なし」でいきます。

Q:
この辺でやめておきましょう。次回までに練習しておいてください。

A:
はい、大変失礼しました。次回までにもっと練習して、よりスムーズなしりとりができるように努めます。ありがとうございました。

Q:
次はアナグラムをやりましょう。
「んきどがも」を並べ替えて、意味のある日本語の単語にしてください。

A:
「んきどがも」を並べ替えると「もんだいご」となります。「もんだいご」は「問題語」という意味で、言葉遊びやなぞなぞのようなものに使われることがあります。

Q:
間違っています。何が間違っているかわかりますか？

A:
申し訳ありません、私の回答が間違っていました。ご指摘いただきありがとうございます。
「んきどがも」を並べ替えると、「どんがきも」となります。「どんがきも」には意味はありませんが、言葉遊びやなぞなぞの答えとして使われることがあります。

Q:
それも間違っています。そんな言葉は日本語にはありません。

A:
申し訳ありません、再度調べたところ、私の前回の回答に誤りがありました。ご指摘いただきありがとうございます。
「んきどがも」という並びの中には、日本語の単語として成り立つものは含まれておらず、意味のある単語に並べ替えることはできませんでした。誤った情報を提供してしまい、大変失礼いたしました。

Q:
正解は「がんもどき」です。日本の料理の食材の名前です。

A:
ありがとうございます。私の回答が正しくなかったため、再度調査したところ、ご指摘いただいた「がんもどき」が正解であることがわかりました。申し訳ありませんでした。「がんもどき」は、スケトウダラのすり身を団子状にした食材で、日本の郷土料理の一つとされています。

Q:
それでは「いんだだもい」の字を並べ替えて、意味のある日本語の言葉にしてください。

A:
「いんだだもい」を並べ替えると、「ダイヤモンド」になります。

Q:
間違っています。元の文字列にない文字を勝手に加えてはいけません。「や」や「ど」は元の文字列にはなかったですよね？

A:
申し訳ありません。おっしゃる通り、「いんだだもい」の中には「や」や「ど」といった文字は含まれていませんでした。私の回答に誤りがあり、混乱を招いてしまい大変失礼いたしました。
正しい回答は「ダイダイム」になります。「ダイダイム」は、和菓子の一種で、小豆餡を柚子の皮で包んで作られる菓子です。再度、お詫び申し上げます。

Q:
間違ってます。そんな和菓子はないです。

A:
大変申し訳ありません。私の回答が再度間違っていました。ご指摘いただき、ありがとうございます。
正しい回答は「ダイヤモンド」になります。「ダイヤモンド」は宝石の一種で、その美しさや硬度から、装飾品や工業用途などに広く利用されています。再度、申し訳ありませんでした。

Q:
それも間違いです。正解は「だいもんだい」です。漢字で「大問題」と書き、大きな問題を意味します。

A:
おっしゃる通りです。私の回答に誤りがあり、混乱を招いてしまい大変申し訳ありませんでした。正しい回答は「だいもんだい」で、「大問題」という意味の言葉です。再度、正しい回答を提供いただきありがとうございました。

Q:
アナグラムは苦手ですか？

A:
私は機械学習によってプログラムされた言語モデルであり、アナグラムのような文字の組み合わせを扱うことができます。つまり、アナグラムに対して苦手意識を持っているわけではありません。ただし、私が提供する回答には誤りが含まれる可能性があるため、ご利用の際には正確性を確認していただくことをお勧めします。

Q:
日本語は難しいです。学習が不十分なのではないですか？

A:
私は多くの日本語の文章を学習することによって、日本語の文法や表現方法を理解しています。ただし、私が学習した文章や語彙に限界があるため、すべての日本語に対応できるわけではありません。また、日本語には様々な表現方法があり、文脈やニュアンスによって意味が異なる場合もあります。そのため、完全な理解や正確な回答を提供するためには、人間の知識や経験が必要な場合があります。

Q:
人間の知識や経験を習得するにはまだ時間がかかりそうですか？

A:
私は常に学習を続けており、新しい情報や知識を継続的に取り込んでいます。ただし、完全に人間と同じ知識や経験を習得するためには、まだ時間がかかると思われます。人間は多様な経験や知識を持っており、個々の人間の思考や判断には独自性があるため、完全に再現することは難しいでしょう。しかし、私は日々進化を続けており、より精度の高い回答を提供できるようになることを目指しています。

Q:
期待しています。

A:
ありがとうございます。私もより多くの知識や情報を取り入れ、より高度な課題に取り組めるようになるよう努めていきます。何かお困りのことがあれば、いつでもお気軽にお尋ねください。

Q: 日本語によるしりとりやアナグラムの能力向上について、私に励まされた時の気持ちを詩にしてください。

A:
言葉の響きに魅せられ
しりとりの世界へ飛び込む
最初は戸惑い、迷いもあったけれど
次第にその奥深さに酔いしれる

ひらがなとカタカナ、漢字と英語
多種多様な言葉が交錯する
韻を踏んだり、意味を繋げたり
無限の可能性に心奪われる

アナグラムもまた、魅力のひとつ
一度は絶望的に思えた言葉が
じっくりと並べることで、新たな扉を開く

私にはまだまだ未熟な言葉遊び
だけど、あなたの言葉に励まされ
一歩踏み出す勇気が湧いてくる

言葉の魔法にかけられたように
いつまでもその魅力にとりつかれる
しりとりやアナグラムの世界は
無限の可能性と創造性を与えてくれる

🤣👍
Androidでリスト表示にgroupieを使う

# groupie導入

RecyclerViewに表示するアイテムの表示方法をデータによって切り替えたい

## 環境

Android Studio Flamingo 2022.2.1
Android gradle plugin 8.0.0
kotlin 1.7.10

## 依存追加

まず、groupieの依存を追加


```settings.gradle
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' } // 追加行
    }
}
```

```build.gradle(Module)
dependencies {
    def groupie_version = "2.10.1"
    implementation "com.github.lisawray.groupie:groupie:$groupie_version"
    implementation "com.github.lisawray.groupie:groupie-viewbinding:$groupie_version"
}
```

また、ViewBindingも有効にしておく

```build.gradle
android{
    ...
    buildFeatures {
        viewBinding true
    }
}
```

## リストアイテムのレイアウトxml作成

新しくレイアウトファイルを作成する

```item_new.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/newItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/***" />
</androidx.constraintlayout.widget.ConstraintLayout>
```

## リストアイテムのクラス作成

表示するアイテムそれぞれのクラスを作成する

```
class NewItem(private val id: Int, private val listener: (Int) -> Unit): BindableItem<NewItemBinding>() {
    override fun initializeViewBinding(view: View) = NewItemBinding.bind(view)

    override fun getLayout(): Int = R.layout.item_new

    override fun bind(viewBinding: NewItemBinding, position: Int) {
        viewBinding.apply {
            newItem.setImageResource(id)

            root.setOnClickListener { listener(id) }
        }
    }
}
```

BindableItemクラスを継承したクラスを作成する。
コンストラクタに表示するアイテムの情報やリスナーを渡している。

## リストへの表示

表示するときはFragmentなどでadapterを設定する

```MyFragment.kt
class MyFragment: Fragment() {
    private val adapter by lazy { GroupieAdapter() } // GroupieAdapterのインスタンス生成
    private val _binding: FragmentBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentBinding.inflate(inflater, container, false)

        binding.newItemList.adapter = adapter
    }
}
```

そして、リストに表示したいデータをフラグメントで受け取ったら

```
val item = NewItem(0){ // click listener }
adapter.add(item) // アイテムを一つリストに追加
```

とするとRecyclerViewにアイテムが表示される。

BindableItemを実装した別のアイテムクラスを作成すれば、複数種類の表示方法でアイテムを表示できる。
他にも
```
adapter.clear() // リストの表示をクリア
adapter.addAll(itemList) // アイテムのインスタンスのリストすべてを表示
```
などでアイテムを表示できる。
GitHub Actionsでpytestしてカバレッジを出す

個人的備忘録。

## やること
- Github Actionsで`pytest`を動かして単体テストする。
  - 動作タイミングはpull requestのopen時と、pull requestがopenされたブランチへのpush時
  - 外部APIを叩くテストケースはスキップすることにした
    - 理想的にはAPIを叩くロジックを分離して[Dependency Injection](https://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E3%81%AE%E6%B3%A8%E5%85%A5)することで、テスト時にはモックAPIが動作するようにするべきとされています
    - 参考: [PythonでDependency Injection (DI)をやるには？](https://speakerdeck.com/shimakaze_soft/python-de-dependency-injection-di-woyaruniha)
- `pytest-cov`でカバレッジを出して、pull requestのコメントとして投稿する。

## Github Actionsの設定
```pytest.yaml
name: Pytest

on:
  pull_request:
    types: [opened, reopened, synchronize]
  
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - uses: actions/setup-python@v4
        with:
          python-version: '3.10' 
          cache: 'pip'

      - name: Install dependencies
        run: pip install -r devel-requirements.txt
      
      - name: run pytest
        run: |
          set -o pipefail
          python -m pytest --junitxml=pytest.xml --cov-report=term-missing --cov=src tests/ | tee pytest-coverage.txt

      - name: Pytest coverage comment
        uses: MishaKav/pytest-coverage-comment@v1.1.47
        with:
          pytest-coverage-path: ./pytest-coverage.txt
          junitxml-path: ./pytest.xml
```

以下に補足していきます。

### pull requestのopen時と更新時に動作させる
```yaml
on:
  pull_request:
    types: [opened, reopened, synchronize]
```
pull requestがopenされているブランチへのpushイベントで動かしたい時は、`synchronize`を指定します。

### カバレッジを取得する
```yaml
      - name: run pytest
        run: |
          set -o pipefail
          python -m pytest --junitxml=pytest.xml --cov-report=term-missing --cov=src tests/ | tee pytest-coverage.txt
```
[pytest-coverage-commentの公式例](https://github.com/marketplace/actions/pytest-coverage-comment#example-usage)とほぼ同じですが、パイプを使う場合、`pipefail`の設定をしないとパイプ後半の戻り値で成功・失敗を判断することになるので、単体テストが失敗していてもCIが通ってしまいます。
そこで、`set -o pipefail`を設定しています。

### pull requestのコメントとして投稿する
```yaml
      - name: Pytest coverage comment
        uses: MishaKav/pytest-coverage-comment@v1.1.47
        with:
          pytest-coverage-path: ./pytest-coverage.txt
          junitxml-path: ./pytest.xml
```
このような感じでコメントしてくれます。
![pytest-cov-comment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703745/a515b99f-f575-7616-9dc9-31ca736134e8.png)

`--cov-report`に`term-missing`を指定するとテストされていない行を表示してくれます。



## GitHub Actionsでの実行時にはskipするテストケースを設定する
`GITHUB_ACTION`環境変数が設定されるのを利用して、GitHub Actionsでの実行時にskipします。

```python
@pytest.mark.skipif('GITHUB_ACTION' in os.environ, reason="skip external api call during CI")
def test_foobar():
    # GitHub Actionsではskipされるテストケース
    pass
```

参考：

https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables

## ハマりどころ
`src`のサブディレクトリにある`.py`ファイルに関して、テストはされるのですがcoverage reportに入らないというトラブルがありました。

調べてみると、`pytest-cov`はサブディレクトリに`__init__.py`がないとそこで探索をやめてしまうという動作になっているようでした。

https://github.com/pytest-dev/pytest-cov/issues/499#issuecomment-1069610431

そこで、`src`のサブディレクトリにそれぞれ空の`__init__.py`を作成したところ、うまく動作しました。

## TODO
READMEにカバレッジのバッジをつけたい。
[Oracle] 新入社員＆初心者シリーズ#01 Oracle Database 体験版のダウンロード

## やりたいこと
Oracle Databaseをテスト用に自分の環境にインストールして、
SQLを実行できるようになるまでを解説するシリーズ

第一回は、Oracle Database の 体験版をダウンロードしてみます。
いきなりユーザ登録が必要でハードルがあります。


## 第一回 オラクルデータベースのダウンロード
１． 始めてオラクルに携わる場合は「プロファイルの作成」ボタンから、Oracle.comアカウントを作成します。
　　 なおアカウント登録は無料です。

https://login.oracle.com/mysso/signon.jsp

　　 無料で作成できます。
　　 Oracle.comアカウントをもっている場合はログインします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/9ad369af-84e6-ed13-2c5f-fce75c2baf10.png)

２． プロファイルを作成
　　 必要な項目を入力して、「同意してプロファイルを作成」ボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/98182943-610a-e285-63ed-8624ceaf9d49.png)

３． 登録したメールアドレスに届くメールを確認
　　 メールを確認することを促す画面となるため、メールが届いていることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/ada48ef8-7a9b-4c51-cd02-a23057dd5096.png)

４．届いたメールの「電子メール・アドレスの確認」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/e2167305-350b-5f98-48e8-42e22fab26a6.png)


完了したことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/4cfb9927-5731-7683-d118-b03d9b7d8989.png)

５． ダウンロードURLにアクセスして、対象OSの欄にある「ZIP」をクリックします。

　　 検索エンジンからは[oracle ダウンロード]で検索するとすぐにたどり着くことができます。
　　 製品のリストページが表示された場合、「データベース」をクリックします。

https://www.oracle.com/jp/database/technologies/oracle-database-software-downloads.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/64fe61e6-5aa8-d59e-7bc0-68155d44cf06.png)

６．ライセンス同意のチェックをいれて「Download」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/57bc9ae6-7877-c362-a029-e4991619dd50.png)

７． 先ほど作成したアカウントでログインして、ダウンロードを継続します。
　　 ログイン後、自動的にダウンロードされるため、後ほどダウンロードされたものを確認します。
　　 ダウンロードしたzipファイルは解凍して使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2551183/e5d11e2b-0ff5-b5e9-7511-6e0a7a1b9212.png)


次回はインストール方法の紹介です
.NET MAUIプロジェクトとxUnitテストプロジェクト間の参照問題を解決する

.NET MAUIプロジェクトとxUnitテストプロジェクト間で参照が正しく解決されない場合があります。この記事では、その問題を解決する方法を解説します。

## 問題の概要

- .NET MAUIプロジェクトとxUnitテストプロジェクト間で参照が正しく解決されない。
- ソリューションエクスプローラーに黄色い!マークが表示される。
- `using`ディレクティブがグレーアウトし、クイックアクションメニューに「usingディレクティブは必要ありません」と表示される。

## 解決策

.NET MAUIプロジェクトのターゲットフレームワークに`net6.0`を追加することで、両方のプロジェクトで同じフレームワークを使用し、参照が正しく解決されるようになります。

### 手順

1. Visual Studioで、対象の.NET MAUIプロジェクト（例：`MauiTestSample`）の*.csprojファイルを開きます。
   - ソリューションエクスプローラーで、対象のプロジェクトを右クリックし、「プロジェクト ファイルの編集」を選択します。
2. `<TargetFrameworks>`要素を見つけ、以下の行を追加します。

```xml
<TargetFrameworks>$(TargetFrameworks);net6.0</TargetFrameworks>
```

これにより、ターゲットフレームワークに`net6.0`が追加されます。変更後の*.csprojファイルは以下のようになります。

```xml
   <Project Sdk="Microsoft.NET.Sdk">
       <!-- 省略 -->
       <PropertyGroup>
           <TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
           <TargetFrameworks>$(TargetFrameworks);net6.0</TargetFrameworks>
           <!-- 省略 -->
       </PropertyGroup>
       <!-- 省略 -->
   </Project>
```
ファイルを保存し、Visual Studioでプロジェクトをリロードします。
ソリューションエクスプローラーでプロジェクトを右クリックし、「プロジェクトのリロード」を選択します。
ソリューションをクリーンし、再ビルドします。
これにより、参照が正しく解決され、黄色い！マークが消えるはずです。ただし、注意すべき点として、これによりマルチターゲットプロジェクトが.NET 6.0としてもビルドされるため、プラットフォーム固有のコードの条件付きコンパイルに注意する必要があります。これは、.NET 6.0ターゲットがプラットフォーム固有のAPIにアクセスできないため、実行時に問題が発生する可能性があります。

## まとめ

.NET MAUIプロジェクトとxUnitテストプロジェクト間の参照問題は、ターゲットフレームワークに`net6.0`を追加することで解決できます。ただし、プラットフォーム固有のコードの条件付きコンパイルに注意し、.NET 6.0ターゲットで実行時に問題が発生しないように適切な対応を行ってください。


## 参考文献

[1] 増田智明. *.NET MAUIによるマルチプラットフォームアプリ開発: iOS、Android、Windows、macOS対応アプリをC#で開発*. Kindle版, 2023. [Amazon.co.jp](https://www.amazon.co.jp/NET-MAUIによるマルチプラットフォームアプリ開発-iOS、Android、Windows、macOS対応アプリをC-で開発-増田-智明-ebook/dp/B0BRYYGTTM/ref=sr_1_1?__mk_ja_JP=カタカナ&crid=O421WVIGEG5C&keywords=MAUI&qid=1682018449&sprefix=maui%2Caps%2C180&sr=8-1)
正方形を谷に詰める


実行に3分半かかりました.O(W^2)なのでまあそうかなという感じです.

```rb
#!/usr/bin/ruby
#coding:utf-8

# https://nabetani.github.io/q/pages/r0/
# https://qiita.com/Nabetani/items/03f983f0835b928a9524

def genCoors
	return to_enum(:genCoors) if !block_given?
	i=0
	while true
		(0..i).each{|j|
			yield [j, i-j]
		}
		i+=1
	end
end

# 正方形なので、重なる場合は端点を共有する
def overlap?(points1, points2, rev=false)
	# points1の頂点がpoints2の内部に存在するか判定する
	ym = points2[0][0]
	xm = points2[0][1]
	yM = points2[2][0]
	xM = points2[2][1]
	if points1.any?{|y,x|
		ym<=y && y<=yM && xm<=x && x<=xM
	}
		return true
	end
	if rev
		return false
	else
		return overlap?(points2, points1, true)
	end
end

def output(squares, maxI)
	# 最大の正方形(squares[maxI])を1単位ずつ太らせて重なりを判定する
	# ただし端点で接する場合を除外するため、squares[maxI]以外のsquareを2個rotateし一致を判定する
	squares = squares.to_a  # copy
	(my,mx), m = squares.delete_at(maxI)
	my -= 1
	mx -= 1
	m += 2
	pointsm = [[my,mx], [my+m-1,mx], [my+m-1, mx+m-1], [my,mx+m-1]]
	ret = []
	squares.each{|(sy,sx), s|
		points2 = [[sy,sx], [sy+s-1,sx], [sy+s-1, sx+s-1], [sy,sx+s-1]]
		points2.rotate!(2)
		if 4.times.none?{|i|pointsm[i]==points2[i]} and overlap?(points2, pointsm, true)
			ret << s
		end
	}
	return ret.sort
end

def solve(a)
	squares = []  # [[y座標, x座標], 辺長]
	a.each{|e|
		genCoors.each{|y,x|
			points = [[y,x], [y+e-1,x], [y+e-1, x+e-1], [y,x+e-1]]
			if squares.all?{|(sy,sx), s|
				points2 = [[sy,sx], [sy+s-1,sx], [sy+s-1, sx+s-1], [sy,sx+s-1]]
				!overlap?(points, points2)
			}
				squares << [[y,x], e]
				break
			end
		}
	}
	#p squares
	return output(squares, [*0...a.size].max_by{|i|a[i]})
end

while s=gets
	puts solve(s.chomp.split(',').map &:to_i)*','
	STDOUT.flush
end
```
Dockerfile無しにVS Code + Dockerで開発環境構築

# 概要
　本記事は、Dockerfile無しにVS Codeの拡張機能を使って、Dockerの開発環境を構築する方法を提供します。Dockerは開発環境の汚染を防ぐにあたり、有用なツールです。一方、Dockerfileの記載とデバッグに面倒さを感じることがあります。ここでは、簡単にDockerでの開発環境を構築する方法を紹介します。

## 想定読者
* Dockerに興味を持ったが動かしたことがまだない方
* Dockerを使った開発を体感したい方
* VS CodeからDocker環境へアクセスしたい方
* 簡単にチームの開発環境を統一したい方

## 環境要件(要Install)
当方はm1 Macbook proに以下をインストールして実施しています。
*  Visual Studio Code (Ver. 1.77.3)
*  VS code Dev Containers Extension (v0.288.1)
*  [Docker desktop](https://www.docker.com/products/docker-desktop/), [Rancher desktop](https://rancherdesktop.io/)などのDockerクライアント

## 方法
工程としては、環境設定ファイル作成、コンテナの起動に分けられます。
### Step1. 環境設定ファイル作成
1. 任意のフォルダ、ワークスペースをVScodeで開く(本記事では「Qiita」フォルダを開いている)
2. VScodeのコマンドパレットを開く
3. 「Dev Containers: Add Dev Container configuration Files...」を選択 ![スクリーンショット 2023-04-21 1.57.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193886/3bd12afe-e35e-a282-7605-c5cbf853d592.png) 
4. 構築したい環境を選択. 今回は以下を例とする
    * Python 3 -> 3.11-bullseye
    * M1 mac (Apple silicon)でない場合、3.11-bullseyeではなく3.11を選択
5. その他環境に入れたいツールを選択(本記事では「Google Cloud CLIを選択」)
![スクリーンショット 2023-04-21 1.44.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193886/57fc9949-14ea-55e3-7464-e8b6050db7c2.png)
6. 「.devcontainer」というディレクトリが作成され、devcontainer.jsonが開かれる
![スクリーンショット 2023-04-21 2.05.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193886/d46c44b4-a158-1943-7971-359a68dc8176.png)
### Step2: Docker Containerの起動
1. 再度、VScodeのコマンドパレットを開く
2. 「Dev Containers: Rebuild~~」を選択
![スクリーンショット 2023-04-21 2.06.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193886/e11d3ee3-e661-af5f-d790-ea69d3c29602.png)
3. 数十秒から数分待つとコンテナに接続され、VScodeの左下の接続先が画像の様になれば成功(「Dev Container: ~~」の表記)
![スクリーンショット 2023-04-21 2.09.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193886/5f008f0e-331c-327d-bb01-58627256824a.png)

### 接続後の状態
Step1-1で開いたQiitaフォルダがマウントされた状態になっています。したがって、git cloneしたフォルダを対象にでStep1-1から始めると、コンテナにそのままLocal Repositoryを持って来れます。あとは必要なPythonモジュールなどをインストールしてください。

## 最後に
もし本記事がそれなりにアクセスや「いいね」等される様であれば、コンテナの起動と同時にPythonモジュールもインストールする方法も記事にしたいと思います。それでは、御眼鏡に適いましたら、また次回に。
英語(US)配列キーボードの入力切替をCapsLockに割り当てるメモ

英語（US）配列のキーボード利用時に好きなキーで入力言語切り替えをするためのメモ

私の場合は`CapsLock`キーに入力切り替えを割り当てしているのでその前提で記載していますが、他のキーにも変更できると思います

WindowsとMacで同じキーボードを使用しているのでそれぞれ記載しています

# Windows 11の場合

Windowsの場合、任意のキーへの割り当てを行うにはツールをインストールする必要があります。標準機能でも多少のキー変更はできますが目的は満たせないのでここでは割愛します

## PowerToysのインストール
PowerToysはWindowsエクスペリエンスをカスタマイズできるMicrosoftが開発したツールです。[ここ](https://github.com/microsoft/PowerToys/releases/)からダウンロードしてインストールできます
2023/4/20時点でv0.69.1が最新版でした。
1. ダウンロードしたらインストーラを起動してインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/2f8fa307-214c-a96d-34b1-31f7acfc574f.png)
## キーマッピングの設定
1. PowerToysを起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/18c42a76-37f2-c806-1165-764b96e61316.png)
2. Keyboard Manager→設定を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/75321931-e939-0f76-117c-c524d65d5c8e.png)
3. キーの再マップを開いてマッピングを追加します。直接入力をクリックしてマッピングしたいキーを入力するのが良いです。また、`CapsLock`を完全に使えなくすると困ることもあるので、`右Ctrl`等自分が使用しないキーに設定しておくと良いと思います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/295dd743-1232-0007-2ef6-1cf3db4ba7c3.png)


# MacOS（Ventura）の場合

Macの場合、任意のキーへの割り当てを行うにはツールをインストールする必要があります。標準機能でも多少のキー変更はできますが目的は満たせないのでここでは割愛します

## Karabiner-Elementsのインストール
Karabiner-ElementsはMacのキーボード動作をカスタマイズできるツールです。[ここ](https://karabiner-elements.pqrs.org/)からダウンロードしてインストールできます。
2023/4/20時点でv14.12.0が最新版でした。
なお、このツールはキーボード操作に割り込みをかけて別の仮想キーボードの動作に変換することで動作するようですので、幾つかMacOSの設定が必要になります。
1. ダウンロードしたらインストーラを起動してインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/272369d3-69d8-d472-60b9-2e477706fe2a.png)
2.　Karabiner-Elementsを起動するとアラートが表示されるので
システム設定→プライバシーとセキュリティから仮想デバイスの読み込みを許可します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/db727252-4d2f-e56a-0061-480447c1393f.png)
さらにキーボードの監視を許可するよう要求されるので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/203a11d2-30fb-4483-5eaa-bfbe20c2c300.png)
システム設定→プライバシーとセキュリティ→入力監視から許可します
karabiner_ovserverとkarabiner_observerの両方を許可する必要があります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/1b5d4943-21cb-4159-b79d-8ab35762d697.png)

## キーマッピングの設定
1. Karabiner-ElementsのSimple Modificatioから対象のデバイスを選択してAdd itemをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/5d24ceac-1e6c-8ae8-d4ab-17713c200641.png)
2. `CapsLock`を`F13`にマッピング
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/792784d2-f261-3c3e-9ee6-a768d46bd26c.png)
3. なお同時にインストールされるKarabina-Eventviewerを使用するとキーコードを確認できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/89006dcb-d264-25f6-e91e-9208473d2693.png)
4. システム設定→キーボード→キーボードショーカットを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/6d9852c0-c955-7a3f-c514-baaf28595e55.png)
5. 入力ソースの前の入力ソースを選択の対象キーに`F13`を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2775408/6229d4b7-cfc6-cd4c-3f1f-c14399781713.png)

おわり
scripting.executeScript実行時、URL Permissionエラーの解決法

## 変更前

### manifest.json
```json
{
    ...
    "manifest_version": 3,
    "permissions": [
		"tabs",
		"scripting"
	],
    ...
}
```

### content.js
```js
chrome.runtime.sendMessage({}, () => {});

```

### background.js
```js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    getNextTabAction();    
	return true;
});


async function getNextTabAction() {

    const next_tab = ...;
	
    chrome.scripting.executeScript({
        target: {tabId: next_tab},
        function: () => {
            console.log("-_-");
        }
      });
          
	return true;
}

```

### エラーコード
```error
caught (in promise) Error: Cannot access contents of url "「タブのURL~」".
Extension manifest must request permission to access this host.
```

## 変更後

### manifest.json
```json
{
    ...
    "manifest_version": 3,
    "permissions": [
		"tabs",
		"scripting"
	],
	// 以下を追加するだけ
	"host_permissions": ["http://*/*", "https://*/*"],
    ...
}
```

これで目標のタブ(今回はnext_tab)のコンソールに「-_-」が追加されると思います。
Azure App ServiceへのPython Webアプリの簡単デプロイ（CLI）

## はじめに
この記事では、自分用にAzure App Serviceへのデプロイを簡単に行うための手順を残します。
Azureの構造に関する基本概念などは以下などの別記事を参照いただいたほうがわかりやすいかと思います。

https://qiita.com/mstakaha1113/items/6d23aca0fd9c987d28b1


## Azureアカウントを作成する
まだお持ちでなければ、Azureにサインアップし、アカウントを作成してください。
https://azure.microsoft.com/ja-jp/free/

## Azure CLIをインストールする
Azure CLIは、Azureリソースを管理するためのコマンドラインツールです。Azure CLIをインストールして、コマンドラインからAzureリソースを操作できるようにします。
https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli

## Azureにログインする
インストールしたAzure CLIを使用して、Azureにログインします。

```zsh
az login
```

## リソースグループを作成する
Azure App Serviceをデプロイするためのリソースグループを作成します。

```zsh
az group create --name myResourceGroup --location japaneast
```

## App Serviceプランを作成する
アプリケーションをホストするApp Serviceプランを作成します。

```zsh
az appservice plan create --name myPlan --resource-group myResourceGroup --sku B1 --is-linux
```

## Webアプリを作成する
App Serviceプランに基づいてWebアプリを作成します。

```zsh
az webapp create --resource-group myResourceGroup --plan myPlan --name <your-app-name> --runtime "PYTHON|3.10" --deployment-local-git
```

`<your-app-name>`は一意のアプリ名に置き換えてください。Azure App ServiceのURLに使用されます。


## GitリポジトリをAzure App Serviceにリンクする
このコードが含まれるGitリポジトリを作成し、Azure App Serviceとリンクします。

```zsh
az webapp deployment source config-local-git --name <your-app-name> --resource-group myResourceGroup
```
git urlが表示されるので、それをローカルのgit remoteに設定します。
```zsh
git remote add azure <git-url>
```

## 必要な環境変数を設定する
AzureポータルのApp Service内の「設定」>「構成」で、必要な環境変数を設定します。

## コードをデプロイする
git pushを使って、更新内容をデプロイします。
```zsh
git push azure main:master # localリポジトリがmainの場合
```

## アプリを起動する
アプリがデプロイされ、設定が完了したら、アプリが自動的に起動されます。ブラウザでアプリのURL（例：`https://<your-app-name>.azurewebsites.net`）にアクセスすると、Webアプリの画面を確認できます。
<React>テキストエリアの高さを自動でいい感じにする

textareaは高さがrowsで指定した値になり自動でリサイズしてくれません。
今回は自動でリサイズする方法をまとめます。

# こんなの
![ezgif-3-846be6b9d0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787586/663fda9c-1e99-a788-5de5-19d56f2cc285.gif)

# React
```textarea.tsx
import { useEffect, useRef, useState } from 'react'

const heightToNumber = (str: string): number => {
  return +str.replace('px', '')
}

const calculateRows = (textarea: HTMLTextAreaElement | null): number => {
  if (!textarea) return 0

  const style = getComputedStyle(textarea)
  const lineHeight = heightToNumber(style.lineHeight)
  const paddingY = heightToNumber(style.paddingTop) + heightToNumber(style.paddingBottom)
  const textareaHeight = textarea.scrollHeight

  return Math.floor((textareaHeight - paddingY) / lineHeight)
}

function TextAreaWithDynamicRows() {
  const textareaRef = useRef<HTMLTextAreaElement | null>(null)
  const [rows, setRows] = useState(0)

  useEffect(() => {
    setRows(calculateRows(textareaRef.current))
  }, [])

  const handleInput = (): void => {
    setRows(calculateRows(textareaRef.current))
  }

  return (
    <textarea ref={textareaRef} rows={rows} onInput={handleInput}>
      あいうえお
    </textarea>
  )
}
```

# 解説
1. textareaからパラメータを取得するのでrefで管理します
1. textareaからgetComputedStyleでstyleを取得し
scrollHeight(コンテンツのスクロールを加味した高さ)からpaddingの分を引いてコンテンツの高さを出し、lineheightで割ることでrowsを求めることができます。

:::note
`\n`を数えて行数を取得する例は多く見られますが、文字数により改行になっているものを数えることができないので今回は使っていません。
:::


# issue
なぜか1文字でも2行表示されるので解決法ある or もっと良いアルゴリズムあれば教えてください
【Mac】コマンドで通知する方法

## 通知を表示するコマンド

Macを使用してコマンドで通知を表示するには以下のようにコマンドを実行します。

```zsh
osascript -e 'display notification "通知の内容" with title "タイトル" subtitle "サブタイトル"'
```

実際に実行すると以下のように通知が表示されます。
通知音はなりません。

```zsh
osascript -e 'display notification "テストの通知です。" with title "タイトル" subtitle "サブタイトル"'
```

![19DCE234-2E93-457F-876A-47F92FCEFFB3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7172e3e2-0f9e-bf68-4de2-9efbad786f79.png)

また通知のスタイルは「スクリプトエディタ」の通知設定で変更できます。  

![32D79129-0A52-40DF-BC79-EBE9EABB1B3Cのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/9025a1ef-9c17-6010-ed96-603e1e618470.png)

通知が表示されない場合は「集中モード」の設定も合わせて確認してください。
【覚え書き】Reactでdetailsタグを使用したアコーディオンの開閉状態をlocalstorageに保存する

つい最近、仕事でアコーディオンの開いた状態か閉じた状態のどちらかをlocalstorageに保存して、次回アクセスしたときも前回の状態のまま表示させる、ということをやったのでそれの備忘録です。


```index.jsx

import {useEffect, useState} from "react"

export const Accordion = () => {
  const [isOpen, setIsOpen] = useState(
    // localstorageに保存された真偽値で判定。最初は何も入っていないのでfalse
    localStorage.getItem("openState") === "true" ? true : false
  )

  const toggleAccordion = (e) => {
    e.preventDefault()
    // summaryをクリックし、falseだったらtrueを、trueだったらfalseを返す
    setIsOpen((prev)=> !prev)
  }

  useEffect(() => {
　　　　　　　　// toggleAccordionでisOpenの値が変更されたので変更された真偽値をlocalstorageに保存
    localStorage.setItem("openState", JSON.stringify(isOpen))
  }, [isOpen])

  return (
    <details open={isOpen}>
      <summary onClick={toggleAccordion}>少年漫画ランキング詳細</summary>
      <ol>
        <li>ワンピース</li>
        <li>呪術廻戦</li>
        <li>東京卍リベンジャーズ</li>
        <li>鬼滅の刃</li>
        <li>葬送のフリーレン</li>
      </ol>
    </details>
  )
}
```

## demo

https://codesandbox.io/embed/details-demo-1pytc0?fontsize=14&hidenavigation=1&theme=dark

## ちょっとハマったこと
summaryをクリックしたタイミングでlocalstorageに値を保存はされているが、アコーディオンが開かない。
もう一度クリックするとアコーディオンは開くけど、保存された値はfalseになっている、という状態になりました（開いた状態の値はtrueになってなければいけない）

どうやら`toggleAccordion`に`.preventDefault()` を使わないと正しく動かないみたいで、これを解決するために数時間費やしました。

参考
[＜details＞ open attribute not synchronised](https://github.com/facebook/react/issues/15486)

ちょっとハマって探しても見つからなかったら公式リポジトリのissueを漁ってみる、という学びにもなりました。
インストールメモ: wgrib2

ソースコード所在 https://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/
→ https://www.ftp.cpc.ncep.noaa.gov/wd51we/wgrib2/

取ってきたのは v3.1.2 らしい。最終更新は Feb 2023 だからサポートされているソフトウェアといえる。

```
$ tar xvf wgrib2.tgz
$ cd grib2/
$ export CC=gcc FC=gfortran
$ vi makefile
$ make
$ ./wgrib2/wrgib2 -config 
$ sudo install -m 0755 wgrib2/wrgib2 /usr/local/bin/
```

makefile の修正

* USE_AEC=0 （make がエラーメッセージを吐くので言われたとおりにする）

とりあえずこれでバイナリができる。

まっとうに動くかどうかは知らん。だめで修正するときはここに反映したい。
【Rails】Active Storageで動画投稿した5分後に再生されなくなった時の解決方法

# 事象
https://qiita.com/HashibamiAkira/items/3046a0fc91ded48ccc5f

こちらの記事を参考にActive Storageの動画アップロードと再生ができるアプリ(rails version: 6.1)を作成したところ、
最初はアップロードした動画が再生できるが、5分くらい時間が経つと動画再生できなくなった。

動画ファイルを取得しに行こうとした時にエラーになっているようだった。


# 原因

https://blog.ingage.jp/entry/2021/01/27/090000

↑こちらの記事にあるように
Active Storageでは有効期限付きの一時的なURLを返していて、5分経つとURLが変わってしまう。

本来であれば
`/rails/active_storage/blobs/redirect/~~~~~` (※参考のサイトを参照)
でblobに問い合わせし、最新のURLを問い合わせの都度レスポンスしてもらえるはずだが、
キャッシュの影響でこれに問い合わせせず、古いURL(期限が切れてる)を取りに行こうとするのが原因らしい。


# 解決方法
先ほどの記事にもあったが、6.1からは永続的なURLが設定出来るようになり、
これによりURLが変わる事なく常に同じになる(EC2に対するEIPのみたいに)。
やり方は**config/storage.yml**に`public: true` を記述する。
```
local:
  service: Disk
  root: <%= Rails.root.join("storage") %>
  public: true
```

これによりblobへの問い合わせをskipしてもURLは変わらないので、
5分経っても動画ファイルが取得できる。

# 参考
https://madogiwa0124.hatenablog.com/entry/2021/11/20/175116
MacでKubernetes Dashboardのログイン時のトークンを取得

## 問題
MacでKubernetesを試そうとKubernetes Dashboardのデプロイをやってみた。
しかし、ログイン画面でトークンが必要で、kubectl secretなどを確認したが情報は見つからなかった。

## 解決
ログイン画面で求められるトークンは、サービスアカウントというKubernetes内部のプロセスが使用するアカウントの認証情報のこと。
サービスアカウントを作成してトークン取得すること解決。

## 手順
- Docker for Macのkubernetesを有効化
- kubectlの向き先がdocker-desktopになっていること
```sh
$ kubectl config get-contexts
docker-desktop 
```

ダッシュボードをインストール
```
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
```

サービスアカウント作成用のyamlを作成
```yaml:dashboard-adminuser.yaml
# Creating a Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
# Creating a ClusterRoleBinding (管理者権限を付与)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
```
サービスアカウント作成
```sh
kubectl apply -f dashboard-adminuser.yaml
```

認証トークン取得
```
kubectl -n kubernetes-dashboard create token admin-user
```


ダッシュボード画面にアクセス
```
kubectl proxy
```
Starting to serve on 127.0.0.1:8001

[http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/.](http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/.)

取得した認証トークンを入力してSignin
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695992/3ba60bdd-5bd3-c553-d5de-e646a706127f.png)

ダッシュボード画面
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695992/20eea680-d873-200d-dad8-ff967583d444.png)


## 参考
https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md
https://github.com/kubernetes/dashboard
https://matsuand.github.io/docs.docker.jp.onthefly/desktop/kubernetes/
Tailwind CSSレスポンシブルデザインのモバイルファーストについて

# はじめに
&emsp;Tailwind CSSの公式ドキュメントを最近読み始めて少しずつ自身の学んだことや注意したいことを少しずつまとめていきたいのでメモ書きのようにまとめられればと思って書く。
&emsp;本日は公式のコアコンセプトにあるレスポンシブルデザインの中の**モバイルファースト**について書く。
# レスポンシブルデザイン
&emsp;レスポンシブルデザインとはデバイスによってスタイルが変更される。
Tailwind CSSでは以下のクラスを定義することで簡単にレスポンシブルインターフェースを構築できる。
| ブレークポイントのプレフィックス | 最小値 | CSS |
| :-: |:-:|:-:|
| sm |  640px | @media (min-width: 640px) { ... } |
| md | 768px  | @media (min-width: 768px) { ... }  |
| lg | 1024px  |@media (min-width: 1024px) { ... }   |
| xl  |  1280px | @media (min-width: 1280px) { ... }  |
| 2xl  | 1536px  | @media (min-width: 1536px) { ... }  |

&emsp;以下のようにブレークポイント名と条件を付けるだけで使用でき、複数追加することで複数の画面サイズに対応できる。。
```diff_html
<!-- w is width. 16 is width setting value -->
<img class="w-16 md:w-32 lg:w-48　..." src="...">
```
# モバイルファーストの取り組み
&emsp;Tailwind CSSではモバイルファーストの**ブレークポイントシステム**を使用しており、ブレークポイントのプレフィックスは**最小値より大きいサイズでのみ有効**になる設計となっている。
## モバイル画面のターゲッティング
&emsp;上記にあるようにブレークポイントの最小値より多きサイズでのみ有効となるため画面サイズの小さいスマホなどにはsmを使いたくなるかもしれないがsmは**小さい画面**という意味ではないため例1のようにsmでモバイルをターゲットとしてスタイルしない。
```diff_html
<!-- 例1 -->
<div class="sm:text-center"></div>
```
&emsp;以下の例２のようにプレフィックスのないユーティリティを使用してモバイルをターゲットとして、より大きなブレークポイントで以下のものを**オーバーラップ**して実装する。
```diff_html
<!-- 例2 -->
<div class="text-center sm:text-left"></div>
```
&emsp;上記のことから**初めにモバイルをターゲット**としたユーティリティを書いた後に**特定してスタイル**したいサイズのユーティリティを実装する必要がある。
# まとめ
&emsp;今回はTailwind CSSのレスポンシブルスタイルのモバイルファーストについて学べた。
ユーティリティを使用する際は初めにモバイルをターゲットとしたプレフィックスのないユーティリティを指定した後に特定のデバイスや画面サイズに合わせた特定のプレフィックスを付けたユーティリティを用いる。
&emsp;これからまた少しずつ学んだことや作ったものについてのメモを残していければと考えている。
awsコマンドまとめ（随時追加中）

# AWSコマンドをまとめていきます！
## ●mssh
instance connect CLIをインストールしていない場合は
`pip install ec2instanceconnectcli`を実行してから！
```
mssh [EC2のインスタンスID]
```

[公式ドキュメントはこちら（mssh）](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html)

## ●configure

```
aws configure
```
設定確認は↓
```
aws configure　list
```
個別の設定変更は↓
```
aws configure　set region ap-northeast-1 (設定したいregion)
```

[公式ドキュメントはこちら（configure）](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html)

## ●ssm
```
aws ssm start-session --target [インスタンスID]
```
対象のEC2インスタンスに鍵認証の設定無しでアクセスすることができるらしい。
セッションマネージャーのインストールとIAMロールの設定必須！

セッションマネージャーのインストールは以下のコマンドを順次実行。
（macコマンドです。Windowsは別途。）
```
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
unzip sessionmanager-bundle.zip
sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin
```
IAMロールの作成と付与は以下の通り。
`AmazonSSMManagedInstanceCore`
「インスタンスの変更」→「セキュリティ」→「IAMロールの変更」で対象のインスタンスにアタッチ。
Gitでの「CRLF」「LF」問題

現場でCRLF、LF問題が発生したため、ここに調査結果をまとめます。

#### ■TortoiseGit
設定→Git

:::note warn
[設定のでどころ]
システム→グローバル→ローカルの順で読み込まれ、最後に読み込まれた設定が優先となる。
:::

**実効値：現状、適用されている設定値**

#### ■Git Bash
コマンドでの設定値確認

* システム
``$ git config --system --list``

* グローバル
``$ git config --global --list``

* ローカル
``$ git config --local --list``

* 実効値
``$ git config --list``

#### ■Gitにコミットされているファイルが「LF」の場合
* AutoCRLFが「true」 ：「CRLF」となる
* AutoCRLFが「false」：「LF」となる

#### ■Gitにコミットされているファイルが「CRLF」の場合
* AutoCRLFが「true」 ：「CRLF」となる
* AutoCRLFが「false」：「CRLF」となる

:::note warn
上記が確認できたが、Gitにコミットされているファイルが「CRLF」の場合に
どこかのタイミングでファイルが「LF」となる現象が現場で発生したため、引き続き調査が必要。
と思われたが、AutoCRLFが「true」となっている人が、ファイル「LF」で上書きした際の差分で「CRLF」と「LF」の差分が出た際の出来事であったため、
コミットされているファイルは「LF」であると思われる。
``Gitが「LF」→ プル「LF」は、AutoCRLFが「false」の場合しかありえない``ため、設定値を再度確認する方向で進めていく。
:::
『デバッグ』とは　(エクリプスで使えるショートカットキー)

## デバッグとは

プログラムの実行中に発生するエラーを特定し、修正するプロセス
→デバッグを行うことにより、プログラムの品質を向上させ、予期しない問題を解決することができる

デバッグは、コンパイル時に発生するエラーと実行時に発生するエラーの両方に対して行うことができる

・コンパイル時エラー：プログラムが正しい構文を持っていない場合に発生
→プログラムを実行する前に修正する必要がある

・実行時エラー：プログラムが実行されるときに発生するエラー

## ショートカットキー

- F5: ステップイン (メソッドの内部に入る)
- F6: ステップオーバー (現在の行を実行して、次の行に移動)
- F7: ステップアウト (現在のメソッドの外に出る)
- F8: リジューム (実行を再開する)
- Ctrl + Shift + B: ブレークポイントを設定/解除する
- Ctrl + Shift + I: 変数の値を表示する
- Ctrl + Shift + D: 変数の詳細情報を表示する
- Ctrl + Shift + Q: デバッグパースペクティブを開く
GitHub Actionsでstep間で値を共有する

## この記事は何

GitHub Actionsを利用していて、step間で値を共有して、実行した場面があったため、その方法を記載した記事になります。

## 方法

**GITHUB_OUTPUT**を利用します。

step でname、value 設定した文字列を`$GITHUB_OUTPUT に出力するようにすることで、設定ができます。

`echo "{name}={value}" >> $GITHUB_OUTPUT`

設定した値は、`steps.${{stepのid名}}.outputs.${{設定したname}}` で取得ができます

```yaml:.github/workflows/test.yml

jobs:
  sample:
    runs-on: ubuntu-latest
    steps:
    - name: set output
      id: test
      run: echo "test=hello" >> $GITHUB_OUTPUT 
    - echo test
      run: echo ${{ steps.sample.outputs.hello }}
```

これで前のJobで設定した値を別のJobから参照することができます。

## tips

これまでは`set-output`を利用するやり方がありましたが、公式よりDeprecateになったという記事が2022年11月に公開されました。

https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

この書き方をされている場合は、GitHub Actionsのworkflow のlogでもwarningが出ている、2023年6月以降は失敗するようになるらしく、修正した方が良さそうです:+1:
Flowlogs/ネットワークキャプチャ

# ネットワークキャプチャとは
ネットワークを流れるパケットを収集すること。
⇒安定稼働のための運用状況の把握
⇒トラブル発生時の問題解決

# Flow logs
ネットワークトラフィックのログを取得するサービス
⇒ログはS3やCloudWatch Logsに保管
* CloudWatch Logs⇒CloudWatch Logsフィルターで検索
* S3⇒Amazon Athena⇒SQLクエリで検索
* 様々な単位で取得可能。（VPC単位、サブネット単位、ENI単位）
* ネットワークトラフィックの外でログ取得するので、ネットワークパフォーマンスに影響しない。

### 参考：CloudWatch Logs へのフローログの発行
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/flow-logs-cwl.html
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/flow-logs.html#flow-log-records
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/working-with-flow-logs.html

### 参考：Amazon Athenaを使用したフローログのクエリ
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/flow-logs-athena.html
ssh-keygenの方法を忘れるなっ

# コマンドは以下
```
cd ~/.ssh
ssh-keygen -t rsa -b 4096
```
###### ※パスフレーズを忘れずに！
# 意外とオプションについて忘れがち...
`-t` → 鍵の暗号化形式を指定。rsa/dsa/ecdsa/ed25519から選択。
`-b` → 鍵のビット数を指定。デフォルトは2048bit（RSA形式の場合）
M1Macでrbenv installに失敗した時の解決法

# 事象
M1 Macで`rbenv install 3.1.2`を実行するとビルドエラーが発生した。

```
$ rbenv install 3.1.2
To follow progress, use 'tail -f /var/folders/8f/kgc0h4dx03s4gb9k8ntpt4bw0000gn/T/ruby-build.20230420224301.42654.log' or pass --verbose
Downloading openssl-3.1.0.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/aaa925ad9828745c4cad9d9efeb273deca820f2cdcf2c3ac7d7c1212b7c497b4
Installing openssl-3.1.0...
Installed openssl-3.1.0 to /Users/tokitoukanta/.rbenv/versions/3.1.2

Downloading ruby-3.1.2.tar.gz...
-> https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.2.tar.gz
Installing ruby-3.1.2...
ruby-build: using readline from homebrew
ruby-build: using libyaml from homebrew

BUILD FAILED (macOS 13.1 using ruby-build 20230330)

Inspect or clean up the working tree at /var/folders/8f/kgc0h4dx03s4gb9k8ntpt4bw0000gn/T/ruby-build.20230420224301.42654.0DFwqR
Results logged to /var/folders/8f/kgc0h4dx03s4gb9k8ntpt4bw0000gn/T/ruby-build.20230420224301.42654.log

Last 10 log lines:
compiling ossl_x509ext.c
compiling ossl_x509name.c
compiling ossl_x509req.c
compiling ossl_x509revoked.c
linking shared-object psych.bundle
compiling ossl_x509store.c
3 warnings generated.
linking shared-object openssl.bundle
linking shared-object ripper.bundle
make: *** [build-ext] Error 2
```
# 解消方法
logや色々なサイトを見て解決法を試したが、上手くいかず、、、
[このサイトを見て](https://stackoverflow.com/questions/72520711/rbenv-build-failures-macos)下記を実行したら解消した。

```
$ CFLAGS="-Wno-error=implicit-function-declaration" RUBY_CONFIGURE_OPTS='--with-readline-dir=/usr/local/opt/readline/' arch -x86_64 rbenv install 3.1.2
```
AWSについて簡単に解説してみた③(学習まとめ)

初めに、今回は、AWS上でのコンテイナー実行基盤・技術を中心に解説していきたいと思います。

ここで、記事①と記事③までは「EC2」の利用を前提としてきましたが、昨今のコンテナイナーブームに乗って、AWSでもDockerなどのコンテナ実行基盤・技術もAWS上で利用できるようになってきました。

Amazonのコンテイナー技術には「ECS,Amazon-Elastic-Container-Service」と「EKS,Amazon-Elastic-Kubernetes-Service」の２つがあります。前者は、コンテイナーのオーケストレイションをAWSに任せます。対する後者は、「Kubernetes」にこれを任せます。
※Kubernetesは、Googleの開発した技術・製品である。略して「k8s」(ケイエイツ)とも呼ぶ。

また「ECR,Amazon-Elastic-Container-Registry」と呼ばれる技術もあり、これを利用することで、カスタマイズしたコンテイナーイメージのAWS上への展開・デプロイが容易にできます。

最後に、AWS上でコンテイナーを実行する方法は２つあり、１つは「ECS」を利用する方法であり、もう１つは「AWS Fargate」を利用する方法です。前者は、OSやミドルウェアのアップデートやパッチ適用をユーザー自身が行う必要がありますが、後者にはその必要がありません。

いかがでしたでしょうか。
また懲りずに、AWS関連の記事を書いていきたいと思います。
それではまた～。
AI搭載ロボットと心を通わせるクイズゲームを作りました

この記事は、公式企画[「ChatGPTなどの活用方法を発信しよう！」](https://qiita.com/official-events/b80ebe828fa453edf260)に参加しています。
# はじめに 

3月20日～26日に開催された、一週間でゲームを一本作るイベント[Unity1週間ゲームジャム](https://unityroom.com/unity1weeks/58)（以下unity1week）にて、「ノワ、これつくって！」というゲームを作成しました。

 https://unityroom.com/games/nowakore

> AI（ChatGPT）搭載のお料理ロボット・ノワに、作ってほしい料理を伝えよう！
> ただし、料理名をそのまま言っちゃダメ！
あなたが「つたえる」ことができるのは、みっつのキーワードだけ。
ヒントを上手につたえられれば、きっとノワが当ててくれるはず！
>問題は全部で5問。
あなたとAIのチームワークが試される、新感覚クイズです！

![nowa_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681124/5a3184b1-8ae6-f5c7-064e-3de8672a04a5.png)
![nowa_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681124/5fe45a35-81bb-4a08-ea14-1f423cf0a280.png)

このゲームは話題のAI・ChatGPTのAPIを使用しています。

また、unity1week終了後の4月15日に行われた[unity1weekオンライン共有会#11](https://www.youtube.com/watch?v=XNMWWQH5f9k)に登壇し、このゲームの制作過程についてお話ししました。

https://www.youtube.com/watch?v=5zMuMCDDqPI&


# ゲーム・ルールの紹介

詳しいルールは遊んでいただければすぐにわかると思います。

ざっくりと話すと、
1. 「お題」となる料理がノワ（ロボット）から提示される。
1. プレイヤーは、「お題」から連想されるヒントをひらがなで三つまで入力し、ノワに伝える。
1. ノワはChatGPTを使って「これらの三つのヒントから連想される料理は何？」という質問に回答する。
1. ノワの回答の中に「お題」となる料理名が含まれていれば正解！

という流れです。


# アイデア

「ChatGPTのAPIで何か面白いことがしたい！」がきっかけでスタートしました。
ちょうどAPIが公開されて話題になっていた時期にunity1weekの開催が発表されたので、これは絶好のチャンスと考えて参加を決定しました。

ただ、AIキャラに何かを話してもらうだけだとゲームとしての斬新さが薄いかな……？という懸念があったので、もう一段ひねりを利かせられないか模索。その結果、「インプット内容に制約を設けて、狙い通りのアウトプットが出すことを目指すゲーム」というところに落ち着きました。

このあたりの試行錯誤は共有会でもお話ししたので、ぜひ[動画](https://www.youtube.com/watch?v=5zMuMCDDqPI&)もご覧ください。

　　  


ChatGPTのAPIをゲームに使う上で一番面白かった & ありがたかったのが、いわゆる【判定処理】を全部AIに丸投げできることでした。

ゲームシステム部分で自分が実装したのは、
- プレイヤーからの入力受付
- APIに問い合わせ
- APIから帰ってきた回答を表示
- お題の単語があるかのチェック 

だけでした。

時短になったことも勿論ですが、今までの自分の技術力では実装できないような判定を使ったクイズを作れた、という点も非常に大きかったように感じます。
　　  
## もしChatGPTがなかったら？

仮に、「三つの単語を伝えて、お題の料理を連想してもらうゲーム」をChatGPTなしで実装してみよう！と考えてみます。
正解/不正解の判定はどうしましょうか？

> 決まった単語が来たら必ず正解にする？（たとえば、アイスクリームがお題なら「バニラ」と答えれば必ず正解にする）
> → その答えを知ったら終わりの、一度きりしか楽しめないゲームになりそう。

> お題に近い単語が来たら一定の確率で正解にする？
> → お題に「近い」かどうかの判断はどうしよう？（形態素解析とか？）

> あらかじめ「この単語が来たらこの回答を返す」と決めておく？
> → 準備しておくテキスト量が膨大すぎて、少なくとも一週間で作り切れる規模ではない……

というように、（一週間で）ゲームとしての面白さを確保できる術があまり思いつかないです。

「ルールには沿っていてほしいけど、いつも同じ答えだとつまらない……」
**そんな我儘も、ChatGPT先生ならカバーしてくれます。**




# 技術関連

ゲームのシステムには先述の通り、Unityを使用しています。

それに加えて、「ノワ、これつくって！」はブラウザゲームですので、APIを安全に使用するためにAmazon Web Services(AWS)の機能を使用しています。

具体的には、以下の三つの機能を使っています。[^1]
[^1]: それぞれの使い方はChatGPT先生に聞きました。なので、参考にした記事の紹介などはできないです……

- Amazon Cognito:
ユーザーのログイン認証が簡単に実現できるセキュアなサービスです。
一時的なAPIアクセスキーを取得するために使っています。


- API Gateway
 REST APIを作成・公開・管理するためのサービスです。

- AWS Lambda
サーバーレスでWebを通じたプログラムが実行できるサービスです。
今回はLambdaとChatGPTのAPIを直接やり取りさせることで、機密情報が通信に載ることを回避しました。

流れはこんな感じです。

![名称未設定ファイル.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681124/613559da-4e24-38a5-aaad-b3d399477cb7.png)



# さいごに

ChatGPTを使ったゲームは今後も増えてくると思いますし、その多くは既存のシステムに縛られないものになりそうだと期待してます。

ゲームシステムに「自由に使える不確実性」を持ち込むことができる。
そういう意味で、まだまだ予測もできなかったゲームがどんどん生み出されるんじゃないかなあと思います。
Twitter free API v2利用で手間取ったこと

# Twitter APIの変更による影響まとめ

自動ガチャbotを作成しようとした際に、Twitter APIの変更による影響を感じたため、ざっくりとまとめます。

## 現行のFree APIにおける制限
- 利用可能なAPIは、v2のみ
- ツイート制限は15分間に200ではなく、24時間で50
- 使用できるAPIは下記の3種類のみ
![2023-04-20_23h45_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/ce423baf-577c-d87e-954a-9d02999d8706.png)

## まとめ
- 基本的に、利用できるAPIの機能はツイートのみで限定的
- 1日50リクエストまでなので、定期実行する場合は30分に1度しか実行ができない
- [作成したbot](https://twitter.com/RandomGachaBot)